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实时显示输出
Oct 02 PHP
php实现jQuery扩展函数
Oct 30 PHP
openPNE常用方法分享
Nov 29 PHP
PHP将XML转数组过程详解
Nov 13 PHP
合并ThinkPHP配置文件以消除代码冗余的实现方法
Jul 22 PHP
PHP检测字符串是否为UTF8编码的常用方法
Nov 21 PHP
PHP 生成N个不重复的随机数
Jan 21 PHP
php结合正则批量抓取网页中邮箱地址
May 19 PHP
php中 ob_start等函数截取标准输出的方法
Jun 22 PHP
PHP表单数据写入MySQL数据库的代码
May 31 PHP
PHP进程通信基础之信号
Feb 19 PHP
PHP中-&gt;和=&gt;的含义及使用示例解析
Aug 06 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中cookie的使用方法
2014/03/29 PHP
php实现水仙花数的4个示例分享
2014/04/08 PHP
简单谈谈PHP中的include、include_once、require以及require_once语句
2016/04/23 PHP
php curl上传、下载、https登陆实现代码
2017/07/23 PHP
javascript 写类方式之二
2009/07/05 Javascript
3款实用的在线JS代码工具(国外)
2012/03/15 Javascript
artDialog 4.1.5 Dreamweaver代码提示/补全插件 附下载
2012/07/31 Javascript
jQuery中get和post方法传值测试及注意事项
2014/08/08 Javascript
Javascript实现的Map集合工具类完整实例
2015/07/31 Javascript
Javascript技术栈中的四种依赖注入详解
2016/02/23 Javascript
走进AngularJs之过滤器(filter)详解
2017/02/17 Javascript
js实现图片懒加载效果
2017/07/17 Javascript
js 索引下标之li集合绑定点击事件
2018/01/12 Javascript
JS遍历DOM文档树的方法实例详解
2018/04/03 Javascript
对vue中v-if的常见使用方法详解
2018/09/28 Javascript
webpack4.0 入门实践教程
2018/10/08 Javascript
vue-cli3使用 DllPlugin 实现预编译提升构建速度
2019/04/24 Javascript
VUE异步更新DOM - 用$nextTick解决DOM视图的问题
2020/11/06 Javascript
[01:04]DOTA2:伟大的Roshan雕塑震撼来临
2015/01/30 DOTA
[04:10]2018年度CS GO玩家最喜爱的主播-完美盛典
2018/12/16 DOTA
win7 下搭建sublime的python开发环境的配置方法
2014/06/18 Python
python使用mailbox打印电子邮件的方法
2015/04/30 Python
Python面向对象特殊成员
2017/04/24 Python
matplotlib中legend位置调整解析
2017/12/19 Python
为什么str(float)在Python 3中比Python 2返回更多的数字
2018/10/16 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
django form和field具体方法和属性说明
2020/07/09 Python
html5 postMessage前端跨域并前端监听的方法示例
2018/11/01 HTML / CSS
经典c++面试题六
2012/01/18 面试题
党员思想汇报范文
2013/12/30 职场文书
竞聘书怎么写,如何写?
2014/03/31 职场文书
避暑山庄导游词
2015/02/04 职场文书
python基础之停用词过滤详解
2021/04/21 Python
HTML5中 rem适配方案与 viewport 适配问题详解
2021/04/27 HTML / CSS
解决MultipartFile.transferTo(dest) 报FileNotFoundExcep的问题
2021/07/01 Java/Android
python实现学员管理系统(面向对象版)
2022/06/05 Python