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和ACCESS写聊天室(三)
Oct 09 PHP
php自动适应范围的分页代码
Aug 05 PHP
php 静态变量与自定义常量的使用方法
Jan 26 PHP
浅析php插件 Simple HTML DOM 用DOM方式处理HTML
Jul 01 PHP
PHP基本语法总结
Sep 06 PHP
Laravel 4 初级教程之安装及入门
Oct 30 PHP
PHP比较运算符的详细介绍
Sep 29 PHP
php 变量引用与变量销毁机制详细介绍
Dec 05 PHP
PHP面相对象中的重载与重写
Feb 13 PHP
PHP根据树的前序遍历和中序遍历构造树并输出后序遍历的方法
Nov 10 PHP
php格式文件打开的四种方法
Feb 24 PHP
PHP使用文件锁解决高并发问题示例
Mar 29 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实现图片添加水印功能
2014/02/13 PHP
discuz图片顺序混乱解决方案
2015/07/29 PHP
从ThinkPHP3.2.3过渡到ThinkPHP5.0学习笔记图文详解
2019/04/03 PHP
ExtJs事件机制基本代码模型和流程解析
2010/10/24 Javascript
浅析return false的正确使用
2013/11/04 Javascript
JS实现适合于后台使用的动画折叠菜单效果
2015/09/21 Javascript
深入浅析JavaScript字符串操作方法 slice、substr、substring及其IE兼容性
2015/12/16 Javascript
通过隐藏iframe实现无刷新上传文件操作
2016/03/16 Javascript
基于jQuery下拉选择框插件支持单选多选功能代码
2016/06/07 Javascript
在windows上用nodejs搭建静态文件服务器的简单方法
2016/08/11 NodeJs
js实现二级导航功能
2017/03/03 Javascript
Vue.js 60分钟快速入门教程
2017/03/28 Javascript
JavaScript闭包_动力节点Java学院整理
2017/06/27 Javascript
bootstrap实现二级下拉菜单效果
2017/11/23 Javascript
详解vue引入子组件方法
2019/02/12 Javascript
了解在JavaScript中将值转换为字符串的5种方法
2019/06/06 Javascript
JQuery常用简单动画操作方法回顾与总结
2019/12/07 jQuery
vue 实现在同一界面实现组件的动态添加和删除功能
2020/06/16 Javascript
Vue.js暴露方法给WebView的使用操作
2020/09/07 Javascript
python3编写C/S网络程序实例教程
2014/08/25 Python
pytorch: tensor类型的构建与相互转换实例
2018/07/26 Python
基于python3实现socket文件传输和校验
2018/07/28 Python
Python基础教程之异常详解
2019/01/10 Python
Django框架orM与自定义SQL语句混合事务控制操作
2019/06/27 Python
pytorch: Parameter 的数据结构实例
2019/12/31 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
2020/02/27 Python
Python3.7.0 Shell添加清屏快捷键的实现示例
2020/03/23 Python
Python如何将字符串转换为日期
2020/07/31 Python
python利用opencv实现颜色检测
2021/02/23 Python
html5 分层屏幕适配的方法
2018/03/16 HTML / CSS
SteelSeries赛睿官网:游戏外设和配件的领先制造商(耳机、键盘、鼠标和鼠标垫)
2018/06/17 全球购物
生物制药专业自我鉴定
2014/02/19 职场文书
教室标语大全
2014/06/21 职场文书
2015年乡镇卫生院妇幼保健工作总结
2015/05/19 职场文书
python本地文件服务器实例教程
2021/05/02 Python
Nginx虚拟主机的配置步骤过程全解
2022/03/31 Servers