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中使用cURL实现Get和Post请求的方法
Mar 13 PHP
下拉列表多级联动dropDownList示例代码
Jun 27 PHP
解析VS2010利用VS.PHP插件调试PHP的方法
Jul 19 PHP
php中数字0和空值的区别分析
Jun 05 PHP
php实现ip白名单黑名单功能
Mar 12 PHP
php简单实现快速排序的方法
Apr 04 PHP
PHP实现简单ajax Loading加载功能示例
Dec 28 PHP
PHP实现双链表删除与插入节点的方法示例
Nov 11 PHP
阿里云的WindowsServer2016上部署php+apache
Jul 17 PHP
Yii2框架自定义类统一处理url操作示例
May 25 PHP
Smarty模板语法详解
Jul 20 PHP
一文搞懂PHP中的抽象类和接口
May 25 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
php判断表是否存在的方法
2015/06/18 PHP
PHP实现通过strace定位故障原因的方法
2018/04/29 PHP
Jquery读取URL参数小例子
2013/08/30 Javascript
js获取日期:昨天今天和明天、后天
2014/06/11 Javascript
上传文件返回的json数据会被提示下载问题解决方案
2014/12/03 Javascript
Javascript堆排序算法详解
2014/12/03 Javascript
分享十五款 jQuery 社交网络分享插件
2015/05/16 Javascript
属于你的jQuery提示框(Tip)插件
2016/01/20 Javascript
谈一谈javascript中继承的多种方式
2016/02/19 Javascript
js表单处理中单选、多选、选择框值的获取及表单的序列化
2016/03/08 Javascript
使用jQuery实现WordPress中的Ctrl+Enter和@评论回复
2016/05/21 Javascript
js定义类的几种方法(推荐)
2016/06/08 Javascript
Vue.js事件处理器与表单控件绑定详解
2017/03/20 Javascript
Vue.js2.0中的变化小结
2017/10/24 Javascript
使用Sonarqube扫描Javascript代码的示例
2018/12/26 Javascript
Node.js API详解之 dgram模块用法实例分析
2020/06/05 Javascript
[00:17]DOTA2荣耀之路5:It’s a disastah!
2018/05/28 DOTA
[01:08:44]NB vs VP 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[51:10]VP vs VGJ.S 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
如何用Python合并lmdb文件
2018/07/02 Python
python入门之井字棋小游戏
2020/03/05 Python
keras分类之二分类实例(Cat and dog)
2020/07/09 Python
Python3.9新特性详解
2020/10/10 Python
OpenCV+python实现膨胀和腐蚀的示例
2020/12/21 Python
canvas实现漂亮的下雨效果的示例
2018/04/18 HTML / CSS
优衣库美国官网:UNIQLO美国
2018/04/14 全球购物
加拿大领先家居家具网上购物:Aosom.ca
2020/05/27 全球购物
《灯光》教学反思
2014/02/08 职场文书
新闻编辑求职信
2014/04/09 职场文书
大班上学期个人总结
2015/02/13 职场文书
故意杀人案辩护词
2015/05/21 职场文书
大学生学习十八届五中全会精神心得体会
2016/01/05 职场文书
多人股份制合作协议书
2016/03/19 职场文书
分析设计模式之模板方法Java实现
2021/06/23 Java/Android
关于HTML编码导致的乱码问题
2021/09/04 HTML / CSS
用Python实现屏幕截图详解
2022/01/22 Python