thinkphp5源码解析(1)数据库
前⾔
tp5的数据库操作全部通过Db类完成,⽐较符合国⼈的习惯,⽐如简单的Db::query()、Db::execute(),还有复杂的链式操作Db::table('user')->where('id=1')->select(),下⾯就通过源码来了解其⼯作流程
看代码之前,先看看涉及到的类都有哪些,tp5的数据库相关的类有以下⼏个:
Db(⽤户接⼝)
Connection(连接器)
Query(查询器)
Builder(SQL⽣成器)
Db::query()发⽣了什么?
假定配置⽂件设置驱动为Mysql,当执⾏以下代码时,tp5的数据库类是怎么⼯作的?
Db::query("select * from user where id=?", [1]);
为了节省篇章以及更好地理解流程,下⾯只展⽰核⼼代码,部分代码被简化或改造,我们来看看Db类:
class Db
{
private static $instance = [];
private static function parseConfig($config)
{
if (empty($config)) {
$config = Config::get('database');
} else {
$config = Config::get($config);
}
php调用mysql数据库
return $config;
}
public static function connect($config = [])
{
$name = md5(serialize($config));
if (!isset(self::$instance[$name])) {
$options = self::parseConfig($config);
}
return self::$instance[$name];
}
{
}
}
因为Db类没有定义query(),所以触发了__callStatic(),__callStatic()⼜调⽤⾃⾝的connect(),connect()实例化Mysql连接器(传⼊数据库配置$options),然后保存到$instance(数据库连接实例数组),再来看看Mysql连接器:
namespace think\db\connector;
class Mysql extends Connection
{
}
Mysql连接器也没有定义query()呀,它继承了Connection,看看Connection 有没有:
public function connect()
{ if (!$this->linkID) { public function query($sql, $bind = [])
{
$this->connect(); }
$this->bindValue($bind); $this->PDOStatement->execute(); return $this->getResult(); }
}Db::query()触发Db::__callStatic(),实例化Mysql 连接器并调⽤Mysql->query(),⽽Mysql 连接器继承了Connection ,所以实际上是调⽤了Connection->query()Db 和Mysql 连接器都没有定义table()⽅法,发现Connection 也有个__call():
protected function getQuery(){ return new \think\db\Query($this);}public function __call($method, $args){
return call_user_func_array([$this->getQuery(), $method], $args);
}所以Db::table('user')实际上是触发了__call()魔术⽅法,然后实例化了⼀个Query 对象(构造函数传⼊当前Mysql 连接器对象),看看Query ⾥⾯做了什么:
⾸先构造函数保存了当前的Mysql 连接器对象,并实例化think\db\builder\Mysql 结论Db::table('user')->where('id=1')->select()发⽣了什么?
Query->table()把表名保存到$options数组,然后返回$this(当前实例)从⽽实现链式操作,where()同样,重点看看select(),它拿到$options 之后把它清空以便下次使⽤,然后调⽤了Builder->select()拿到拼装好的sql,交由Connection->query()查询数据库获得结果集,整个流程到此结束,那么Builder是怎么拼装sql的呢?
think\db\builder\Mysql并没有定义select(),不过它继承了Builder,看看Builder代码:
Builder通过$options替换sql模板拿到sql
结论
Db::table()触发了__callStatic()实例化Connection并调⽤table(),由于Connection也没有定义table(),⼜触发了⾃⾝的__call()实例化Query 并调⽤table(),table()返回$this实现链式操作DB::table()->where()->select(),⽽select⼜调⽤Builder->select()拿到sql,最终调⽤Connection->query()获取查询结果,固完整的类图表⽰如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论