thinkphp3.2.0 setInc方法 源码全面解析


Posted in PHP onJanuary 29, 2018

我们先来看一下setInc的官方示例:

thinkphp3.2.0 setInc方法 源码全面解析

需要一个字段和一个自增的值(默认为1)

我们通过下面这个例子来一步步分析他的底层是怎么实现的:

<?php
namespace Home\Controller;
use Think\Controller;

class TestController extends Controller {
  public function test() {
    $tb_test = M('test');
    $tb_test->where(['id'=>1])->setInc('test_number',2); //每次添加2
    dump($tb_test->getLastSql());
    //string(67) "UPDATE `tb_test` SET `test_number`=test_number+2 WHERE ( `id` = 1 )"
  }
}

第一步肯定是要找到setInc方法的源码:

这里我用到了phpstrom全局搜索的方法,找到了setInc是在proj\ThinkPHP\Library\Think\Model.class.php下

/**
   * 字段值增长
   * @access public
   * @param string $field 字段名
   * @param integer $step 增长值
   * @return boolean
   */
  public function setInc($field,$step=1) {
    return $this->setField($field,array('exp',$field.'+'.$step));
  }

可以看到这里用到了setField这个方法,然后用exp自定义表达式设置 $field = $field + $step 到这里,我们稍微了解了一点原理。

可是问题又来了setField又是怎么实现的呢?在同个文件下,找到setField方法:

/**
   * 设置记录的某个字段值
   * 支持使用数据库字段和方法
   * @access public
   * @param string|array $field 字段名
   * @param string $value 字段值
   * @return boolean
   */
  public function setField($field,$value='') {
    if(is_array($field)) {
      $data      =  $field;
    }else{
      $data[$field]  =  $value;
    }
    return $this->save($data);
  }

这里我们看到了常用到的save方法,这里的 $data[$field] = $value; 其实就是 $data['test_number'] = array("exp","test_number+2")

接着来看最常用的save方法:

/**
   * 保存数据
   * @access public
   * @param mixed $data 数据
   * @param array $options 表达式
   * @return boolean
   */
  public function save($data='',$options=array()) {
    if(empty($data)) {
      // 没有传递数据,获取当前数据对象的值
      if(!empty($this->data)) {
        $data      =  $this->data;
        // 重置数据
        $this->data   =  array();
      }else{
        $this->error  =  L('_DATA_TYPE_INVALID_');
        return false;
      }
    }
    // 数据处理
    $data    =  $this->_facade($data);
    // 分析表达式
    $options  =  $this->_parseOptions($options);
    $pk     =  $this->getPk();
    if(!isset($options['where']) ) {
      // 如果存在主键数据 则自动作为更新条件
      if(isset($data[$pk])) {
        $where[$pk]     =  $data[$pk];
        $options['where']  =  $where;
        unset($data[$pk]);
      }else{
        // 如果没有任何更新条件则不执行
        $this->error    =  L('_OPERATION_WRONG_');
        return false;
      }
    }
    if(is_array($options['where']) && isset($options['where'][$pk])){
      $pkValue  =  $options['where'][$pk];
    }    
    if(false === $this->_before_update($data,$options)) {
      return false;
    }    
    $result   =  $this->db->update($data,$options);
    if(false !== $result) {
      if(isset($pkValue)) $data[$pk]  = $pkValue;
      $this->_after_update($data,$options);
    }
    return $result;
  }

最主要是的$options = $this->_parseOptions($options);和$result = $this->db->update($data,$options); 前者把参数转换成用于拼接sql的字符串数组,后者调用了proj\tptest\ThinkPHP\Library\Think\Db.class.php下的update方法:

/**
   * 更新记录
   * @access public
   * @param mixed $data 数据
   * @param array $options 表达式
   * @return false | integer
   */
  public function update($data,$options) {
    $this->model =  $options['model'];
    $sql  = 'UPDATE '
      .$this->parseTable($options['table'])
      .$this->parseSet($data)
      .$this->parseWhere(!empty($options['where'])?$options['where']:'')
      .$this->parseOrder(!empty($options['order'])?$options['order']:'')
      .$this->parseLimit(!empty($options['limit'])?$options['limit']:'')
      .$this->parseLock(isset($options['lock'])?$options['lock']:false)
      .$this->parseComment(!empty($options['comment'])?$options['comment']:'');
    return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array()));
  }

最后其实就是用到了proj\ThinkPHP\Library\Think\Db\Driver\Mysql.class.php这个驱动类的execute方法。

/**
   * 执行语句
   * @access public
   * @param string $str sql指令
   * @return integer|false
   */
  public function execute($str) {
    $this->initConnect(true);
    if ( !$this->_linkID ) return false;
    $this->queryStr = $str;
    //释放前次的查询结果
    if ( $this->queryID ) {  $this->free();  }
    N('db_write',1);
    // 记录开始执行时间
    G('queryStartTime');
    $result =  mysql_query($str, $this->_linkID) ;
    $this->debug();
    if ( false === $result) {
      $this->error();
      return false;
    } else {
      $this->numRows = mysql_affected_rows($this->_linkID);
      $this->lastInsID = mysql_insert_id($this->_linkID);
      return $this->numRows;
    }
  }

最后用最底层的mysql_query执行SQL语句。

到此为止,setInc的源码已经大致过了一遍了。想必大家对setInc如何执行也更了解了一点。

以上这篇thinkphp3.2.0 setInc方法 源码全面解析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

PHP 相关文章推荐
PHP动态创建Web站点的方法
Aug 14 PHP
一个简洁的PHP可逆加密函数(分享)
Jun 06 PHP
php中sql注入漏洞示例 sql注入漏洞修复
Jan 24 PHP
ThinkPHP中的create方法与自动令牌验证实例教程
Aug 22 PHP
php合并数组中相同元素的方法
Nov 13 PHP
PHP开启opcache提升代码性能
Apr 26 PHP
PHP的文件操作与算法实现的面试题示例
Aug 10 PHP
PHP 的比较运算与逻辑运算详解
May 12 PHP
thinkPHP模板算术运算相关函数用法分析
Jul 12 PHP
PHP自定义函数实现数组比较功能示例
Oct 19 PHP
PHP删除字符串中非字母数字字符方法总结
Jan 20 PHP
php中文语义分析实现方法示例
Sep 28 PHP
Ubuntu上安装yaf扩展的方法
Jan 29 #PHP
PHP实现的防止跨站和xss攻击代码【来自阿里云】
Jan 29 #PHP
php实现的AES加密类定义与用法示例
Jan 29 #PHP
php 判断IP为有效IP地址的方法
Jan 28 #PHP
Laravel中unique和exists验证规则的优化详解
Jan 28 #PHP
win10 apache配置虚拟主机后localhost无法使用的解决方法
Jan 27 #PHP
PHP设计模式之注册树模式分析
Jan 26 #PHP
You might like
apache+php+mysql安装配置方法小结
2010/08/01 PHP
PHP的substr_replace将指定两位置之间的字符替换为*号
2011/05/04 PHP
第4章 数据处理-php数组的处理-郑阿奇
2011/07/04 PHP
用Json实现PHP与JavaScript间数据交换的方法详解
2013/06/20 PHP
ThinkPHP中公共函数路径和配置项路径的映射分析
2014/11/22 PHP
php算法实例分享
2015/07/14 PHP
PHP文件缓存类实现代码
2015/10/26 PHP
修改jquery里的dialog对话框插件为框架页(iframe) 的方法
2010/09/14 Javascript
回车直接实现点击某按钮的效果即触发单击事件
2014/02/27 Javascript
js函数定时器实现定时读取系统实时连接数
2014/04/30 Javascript
Javascript中的arguments与重载介绍
2015/03/15 Javascript
浅谈被jQuery抛弃的函数及替代函数
2015/05/03 Javascript
javascript实现类似百度分享功能的方法
2015/07/27 Javascript
BootStrap下jQuery自动完成的样式调整
2016/05/30 Javascript
详解jQuery简单的表单应用
2016/12/16 Javascript
原生JS实现几个常用DOM操作API实例
2017/01/19 Javascript
javascript事件的绑定基础实例讲解(34)
2017/02/14 Javascript
TypeScript入门-基本数据类型
2017/03/28 Javascript
vue中如何实现后台管理系统的权限控制的方法示例
2018/09/19 Javascript
微信小程序如何使用云开发
2019/05/17 Javascript
Vue配置marked链接添加target=&quot;_blank&quot;的方法
2019/07/19 Javascript
解决Vue watch里调用方法的坑
2020/11/07 Javascript
Vue与React的区别和优势对比
2020/12/18 Vue.js
[07:47]DOTA2国际邀请赛采访专栏:探访Valve总部
2013/08/08 DOTA
[32:39]完美世界DOTA2联赛循环赛 Forest vs Inki BO2第一场 11.04
2020/11/04 DOTA
Python实现的石头剪子布代码分享
2014/08/22 Python
Python的Django框架中settings文件的部署建议
2015/05/30 Python
pytorch 转换矩阵的维数位置方法
2018/12/08 Python
python递归法实现简易连连看小游戏
2020/03/25 Python
python 利用pywifi模块实现连接网络破解wifi密码实时监控网络
2019/09/16 Python
Python数据可视化:顶级绘图库plotly详解
2019/12/07 Python
使用TensorFlow对图像进行随机旋转的实现示例
2020/01/20 Python
Java基础类库面试题
2013/09/04 面试题
优秀党员学习焦裕禄精神思想汇报范文
2014/09/10 职场文书
公司规章制度范本
2015/08/03 职场文书
webpack介绍使用配置教程详解webpack介绍和使用
2022/06/25 Javascript