前言
从TP3.2到TP5,已经使用了TP框架快两年了。自认为使用TP处理一般的业务不成问题了。
可是,却从来没有深究过TP是如何实现这些功能的,仅仅只是会调用API而已,也不敢动框架的代码。
所以现在就整理一系列的文章来研究一下TP5的底层源码,设计模式,思想等。
额!算是开始一个坑吧。从最经典的Db类开始吧! gogogo!
对Db类的初识
一直觉得TP5的Db类是很方便的,只需要更改一下database配置文件即可连接各种数据库。
个人觉得还是挺强大的,他是如何通过配置文件更改一个值就能调用不同的数据库,这让我很是疑惑。
所以来研究一下吧,不过我刚看了一本书《PHP的核心技术与最佳实践》,了解了通过工厂模式是可以完成这个要求的。
不过还是看一下TP5是怎么实现的吧。
Db类的相关文件分析
本系列的部分细节参考了此文档戳我可见
文件thinkphp是TP5的核心库
而thinkphp\think
目录下是我们各个类的入口1
此目录下有一个Db.php是Db类的入口。
TP5的Db类文件夹目录为:thinkphp\think\db1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21此文件夹为Db类的具体实现
有如下文件
db
builder Db驱动类
Mysql.php Mysql数据库驱动
Pgsql.php Pgsql数据库驱动
Sqlite.php Sqlite数据库驱动
Sqlsrv.php Sqlsrv数据库驱动
connector Db连接器类
Mysql.php Mysql数据库连接
Pgsql.php Pgsql数据库连接
pgsql.sql Pgsql类型转换
Sqlite.php Sqlite数据库连接
Sqlsrv.php Sqlsrv数据库连接
exception Db错误类
BindParamException.php Pdo参数绑定异常
DataNotFoundException.php 字段没有找到
ModelNotFoundException.php 模型不存在
Builder.php Db的抽象驱动类,通过此类构建对应的Db驱动类
Connection.php Db的抽象连接器类,通过此类连接对应Db连接器类
Query.php 将所有的Sql方法封装成一个类。
Db入口类分析
一般我们调用Db类是需要use thinkphp\Db
,这文件就是我们的入口文件,所以我们看看他的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32namespace think;
use think\db\Connection;
use think\db\Query;
class Db {
// 数据库连接实例
private static $instance = [];
// 查询次数
public static $queryTimes = 0;
// 执行次数
public static $executeTimes = 0;
// 数据库初始化,并取得数据库类实例
public static function connect($config = [], $name = false){
.....先省略
}
// 清除所有的实例
public static function clear() {
self::$instance = null; // 很粗暴嘛
}
// 数据库连接参数解析
private static function parseConfig($config){
....先省略
}
// DSN解析 把返回的参数解析一下 提取需要连接的关键字
private static function parseDsn($dsnStr){
...先省略
}
// 调用驱动类的方法
public static function __callStatic($method, $params){
...先省略
}
}
这就是Db入口类的基本目录结构。
首先分析头部,命名空间为think,class为Db说明我们的入口没错。然后use两个类,一个连接器类,一个Query类。
看一看此类的各个方法,发现主要是初始化+解析config的配置。
首先看看Db入口类是如何获取到database里面的参数的
1 | // database的配置是通过parseConfig方法获取到的,代码如下 |
这里是通过了一个助手函数config把database里面的参数返回了,这样我们就得到了database的参数。
那我们看看database里面是什么样的呢?
1 | database在application目录下有,当然每一个模块下面也可以新建。 |
可以看见database文件把数据return了回来,所以可以获取到里面配置的所有内容,这样的解耦使我们的配置更加简便,不错!
然后看看最核心的连接类是如何执行的呢?
1 | // 如何通过配置文件即可连接相对于的数据库类呢? |
好吧,还是很经典的工厂模式。通过传入的配置参数,引入对应的文件。学习了,的确很方便!
到目前为止已经能够获取database的参数了,也能初始化不同的连接器了,还差一个查询方法了。
是的,还有一个use think\db\Query
还没使用呢!对吧。
驱动类的实现
1 | // TP5把所有的SQL都通过PDO封装了,意思是无论你是什么数据库,查询的关键字都是这些!方便吧。 |
魔术方法,调用静态方法,每次调用前都会初始化数据库,并传入方法和参数。
然后因为引入的连接器不同,所以会调用相对于的构建类他们都继承builder,而builder封装了所有的查询方法。
这样就可以实现封装所有数据库的查询方法了!
接下来看看那两个use分别是什么吧
Connection连接类
1 | // db文件下有connector文件夹,封装了每一种数据库的连接方式,他们都继承于connection |
有很多很多代码,上面主要是默认的config和PDO连接参数的初始化。 因为是抽象类所以实例化的是他们的各个子类。
builder的工厂模式
1 | public function getBuilder() |
这里是通过子连接器的属性,用工厂模式引入的相对于的构建器和Db入口类的思想也是一样的。
其余的都是各种的数据库基本操作了
Query类
Query类封装了各种Sql原生语句实现的方法,算是独立出来的,因为model也可以使用这个。
Db类总结
TP5的Db类差不多就是如上,思想主要是通过工厂模式来通过同一入口,创建不同的实例,其中查询时封装了一层Pdo层,
即方便了用户使用,也可以增强安全性。总之十分收益。不过我的描述不行,很多想写的不知道怎么写,再接再厉。
TP5源码分析系列第一步OK。