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中使用Oracle数据库(4)
Oct 09 PHP
PHP函数spl_autoload_register()用法和__autoload()介绍
Feb 04 PHP
深入了解 register_globals (附register_globals=off 网站打不开的解决方法)
Jun 27 PHP
php 批量生成html,txt文件的实现代码
Jun 26 PHP
PHP使用GIFEncoder类处理gif图片实例
Jul 01 PHP
浅谈使用 PHP 进行手机 APP 开发(API 接口开发)
Aug 11 PHP
php单例模式实现方法分析
Mar 14 PHP
php同时使用session和cookie来保存用户登录信息的实现代码
May 13 PHP
PHP 实现页面静态化的几种方法
Jul 23 PHP
PHP设计模式之工厂模式(Factory Pattern)的讲解
Mar 21 PHP
详解php中生成标准uuid(guid)的方法
Apr 28 PHP
Laravel timestamps 设置为unix时间戳的方法
Oct 11 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统计目录下的文件总数及代码行数(去除注释及空行)
2011/01/17 PHP
php header Content-Type类型小结
2011/07/03 PHP
PHP 第二节 数据类型之字符串类型
2012/04/28 PHP
PHP基于单例模式编写PDO类的方法
2016/09/13 PHP
thinkphp查询,3.X 5.0方法(亲试可行)
2017/06/17 PHP
JavaScript 调试器简介
2009/02/21 Javascript
Javascript 修改String 对象 增加去除空格功能(示例代码)
2013/11/30 Javascript
兼容主流浏览器的iframe自适应高度js脚本
2014/01/10 Javascript
jquery自动填充勾选框即把勾选框打上true
2014/03/24 Javascript
使用node.js 获取客户端信息代码分享
2014/11/26 Javascript
jquery判断复选框选中状态以及区分attr和prop
2015/12/18 Javascript
javascript中利用柯里化函数实现bind方法【推荐】
2016/04/29 Javascript
js正则表达式注册页面表单验证
2016/10/11 Javascript
JS识别浏览器类型(电脑浏览器和手机浏览器)
2016/11/18 Javascript
Javascript实现倒计时(防页面刷新)实例
2016/12/13 Javascript
javascript replace()第二个参数为函数时的参数用法
2016/12/26 Javascript
Vue 应用中结合vux使用微信 jssdk的方法
2018/08/28 Javascript
layui问题之自动滚动二级iframe页面到指定位置的方法
2019/09/18 Javascript
Vue自定义指令结合阿里云OSS优化图片的实现方法
2019/11/12 Javascript
VUE实现Studio管理后台之鼠标拖放改变窗口大小
2020/03/04 Javascript
[02:03]风行者至宝清风环佩外观展示
2020/09/05 DOTA
python 默认参数相关知识详解
2019/09/18 Python
解析浏览器的一些“滚动”行为鉴赏
2019/09/16 HTML / CSS
美国电视购物:QVC
2017/02/06 全球购物
女性时尚网购:Chic Me
2019/07/30 全球购物
应届生高等护理求职信
2013/10/12 职场文书
党的群众路线教育实践活动批评与自我批评
2014/02/16 职场文书
硕士研究生就业推荐信
2014/05/18 职场文书
学雷锋活动倡议书
2014/08/30 职场文书
流动人口婚育证明范本
2014/09/26 职场文书
党员检讨书
2014/10/13 职场文书
2014年学校禁毒工作总结
2014/12/23 职场文书
借条格式范本
2015/05/25 职场文书
五一晚会主持词
2015/07/01 职场文书
python中Tkinter 窗口之输入框和文本框的实现
2021/04/12 Python
JavaWeb 入门:Hello Servlet
2021/07/16 Java/Android