thinkphp3.2.0 setInc方法 源码解析

我们先来看一下setInc的官方示例:
tp看云文档

需要一个字段和一个自增的值(默认为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如何执行也更了解了一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值