Thinkphp是我们经常用使用的一个php的MVC框架。通常我们把业务分类,分层,在不同的层处理不同的业务逻辑。
本文要讲的是model层,关于获取上次执行的SQL语句的问题。(用于日志记录,或者分析出错原因等)。
1:model层的一般情况
通常,我们是通过集成系统Model类的方式来实现的。比如:class UserModel extends Model;(此文不多考虑命名空间的问题,即忽略3.1和3.2的差别)
更有甚至,有一个model的基类。class BaseModel extends Model,然后:class UserModel extends BaseModel,
当然,也有些初学者,或者业务逻辑简单的情况,直接在C层,M一个系统model类,然后处理业务逻辑。
本文不讨论没有M层的情况。
2:getLastSql函数
看过Thinkphp中Model类的人,都能发现这个函数,甚至还有,getLastInsID,getDbError,getError,getPk,getDbFields等函数。这些函数都是我们经常可能会用到的model层的函数。这里只说getLastSql函数。
此函数返回上次执行的SQL语句。
但是这句话不是太好理解的。
如果,我们使用,debug_backtrace,生成一条回溯跟踪线。经常会发现:
[Sweep] => SHOW COLUMNS FROM `sweep_info`
[sweep_info] => SELECT * FROM `sweep_info` WHERE `sweep_result` = '' AND `status` = 0
有两条SQL语句。很显然,第一条不是我们需要的。(实际上,第一条是获取数据库表中的字段名,用于字段的验证,这是TP的可配置功能)
那么,如何获取第二条SQL语句?
3:多个model类的继承关系:
上面的问题,需要考虑到之前我们提到的常见model情况。情况里,存在了两级甚至三级的继承关系。(实际上,这个继承关系也只是第一条SQL语句需要考虑的)。
那么,现在我们先来弄清楚一个问题。这两条SQL语句都是谁执行的?
这个问题其实很简单:我们代码里的哪些函数可能会执行SQL语句?那么,这些方法在哪个类里声明的?很显然,是Think的model类。也就是继承关系最上面的那个类。
那么,这两个SQL语句都是系统的model类执行的?
是的。准确点儿说,是这个类的两个对象一人执行了一条。(这个说法不太准确,准确的说,是每个对象里的DB对象,DB是个单例,都是这个单例执行的。只不过,我们在获取这两条SQL的时候,是用model对象获取,而非DB对象,所以,简单的理解成“两个对象一人执行了一条”)
4:获取第二条SQL语句
上面我们说了很多,其实都是一个理解的过程。真实的操作很简单。如下:
class UserModel extends Model(BaseModel){
public function test($data){
$model = M('user');
$model->add($data);
$sql = $model->getLastSql();
}
}
这里的$sql就是我们需要的第二条。是吧,真实的实现,其实是很简单的。
5:思考:为什么会这样?
问题即是:为什么是两个model对象,为什么是两条SQL语句?为什么这样就可以得到我们刚才执行的SQL语句?(上面的例子代码,其SQL应该形如:Insert into user(...) values(...))
答案:
UserModel在实例化的时候,其实就是model的一个实例化过程。第一条SQL语句,可以理解成UserModel在实例化的时候执行的,获取了一下表中的字段信息(这种说法不太准确,想要了解,还是去看源码)。这是第一个对象,也是第一条SQL语句。
而在test函数里,我们实例化了一个Model,($model = M('user');其实,D和M方法,就是一个实例化的过程)这是第二个对象,对应的:$model->add($data);当然就是执行第二条SQL语句的地方。(这个往往也是我们想要查看的SQL语句)。
再多说一点,其实getLastInsID,getDbError,getError,getPk,getDbFields这些函数的实现过程,在理解上,也就是上面的关系和情况。理解清楚是“这两个对象里的哪个对象”,可以避免:$this-> 调用还是 $model->调用的问题。