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连接MongoDB示例代码
Sep 06 PHP
PHP 提取图片img标记中的任意属性的简单实例
Dec 10 PHP
CI(CodeIgniter)框架配置
Jun 10 PHP
php有道翻译api调用方法实例
Dec 22 PHP
PHP版QQ互联OAuth示例代码分享
Jul 05 PHP
thinkPHP中验证码的简单使用方法
Dec 26 PHP
PHP 设计模式系列之 specification规格模式
Jan 10 PHP
Zend Framework教程之Zend_Controller_Plugin插件用法详解
Mar 07 PHP
PHP请求Socket接口测试实例
Aug 12 PHP
完美解决phpexcel导出到xls文件出现乱码的问题
Oct 29 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
Sep 29 PHP
Laravel框架生命周期与原理分析
Jun 12 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
让Nginx支持ThinkPHP的URL重写和PATHINFO的方法分享
2011/08/08 PHP
PHP的curl实现get,post和cookie(实例介绍)
2013/06/17 PHP
如何使用“PHP” 彩蛋进行敏感信息获取
2013/08/07 PHP
PHP 实现代码复用的一个方法 traits新特性
2015/02/22 PHP
PHP书写格式详解(必看)
2016/05/23 PHP
JQuery实现自定义对话框的代码
2008/06/15 Javascript
javascript实现的使用方向键控制光标在table单元格中切换
2010/11/17 Javascript
jQuery 翻牌或百叶窗效果(内容三秒自动切换)
2012/06/14 Javascript
JavaScript中的setUTCDate()方法使用详解
2015/06/11 Javascript
JS实现不规则TAB选项卡效果代码
2015/09/16 Javascript
JavaScript中eval()函数用法详解
2015/12/14 Javascript
浅谈jquery点击label触发2次的问题
2016/06/12 Javascript
基于JavaScript实现在新的tab页打开url
2016/08/04 Javascript
jquery实现页面加载效果
2017/02/21 Javascript
基于pako.js实现gzip的压缩和解压功能示例
2017/06/13 Javascript
深入浅析Vue中的Prop
2018/06/10 Javascript
更改BootStrap popover的默认样式及popover简单用法
2018/09/13 Javascript
详解 微信小程序开发框架(MINA)
2019/05/17 Javascript
angular使用md5,CryptoJS des加密的方法
2019/06/03 Javascript
layui 上传图片 返回图片地址的方法
2019/09/26 Javascript
JavaScript数值类型知识汇总
2019/11/17 Javascript
vue项目页面嵌入代码块vue-prism-editor的实现
2020/10/30 Javascript
python编程线性回归代码示例
2017/12/07 Python
django执行原始查询sql,并返回Dict字典例子
2020/04/01 Python
Opencv+Python识别PCB板图片的步骤
2021/01/07 Python
python3中celery异步框架简单使用+守护进程方式启动
2021/01/20 Python
卡西欧B级产品官方网站:Casio Outlet
2018/05/22 全球购物
Guess美国官网:美国知名服装品牌
2019/04/08 全球购物
Timberland德国官网:靴子、鞋子、衣服、夹克及配件
2019/12/10 全球购物
早餐连锁店计划书
2014/01/08 职场文书
大学生旅游业创业计划书
2014/01/29 职场文书
小学生演讲稿大全
2014/04/25 职场文书
客户经理竞聘演讲稿
2014/05/15 职场文书
教师个人总结范文
2015/02/11 职场文书
详解Flutter自定义应用程序内键盘的实现方法
2022/06/14 Java/Android
MySQL数据库实验之 触发器和存储过程
2022/06/21 MySQL