TP5的數(shù)據(jù)庫(kù)相關(guān)操作類由 Connection(連接器)、Query(查詢器)、Builder(sql生成器)組成。
Db流程如圖:

Paste_Image.png
還是以一個(gè)簡(jiǎn)單的Db查詢?yōu)槔?,?duì)流程圖代碼分解展示:
<b>Step:1、2</b>
file [library\think\Db.php]
namespace think;
use think\Collection;
use think\db\Query;
/*
Db捕捉到不存在的function會(huì)__callStatic(){}執(zhí)行數(shù)據(jù)庫(kù)初始化connect(){} 然后單例化Connector Mysql類
*/
class Db{
static $instance = [];
/*
@param $config 數(shù)據(jù)庫(kù)連接參數(shù)配置
@param $name 強(qiáng)制重連接標(biāo)示
return Connection對(duì)象實(shí)例
*/
static function connect($config = [], $name = false)
{
//單例 Connection 類,但如果設(shè)置了重連接標(biāo)示的話就重新實(shí)例化
if (true === $name || !isset(self::$instance[$name])) {
//parseConfig獲取數(shù)據(jù)庫(kù)連接相關(guān)配置參數(shù),如果$config是空的則直接讀取配置文件
$options = self::parseConfig($config);
//獲取配置參數(shù)數(shù)據(jù)庫(kù)類型type 然后new對(duì)應(yīng)的connecter $type 類 這個(gè)$type類繼承connecter抽象類
$class = '\\think\\db\\connector\\' . $options['type'] ;
} else {
if (true === $name) {
return new $class($options);
} else {
self::$instance[$name] = new $class($options);
}
}
return self::$instance[$name];
}
/*
__call(){}魔術(shù)。詳見(jiàn)php官方文檔
*/
static function __callStatic($method, $params)
{
return call_user_func_array([self::connect(), $method], $params);
}
}
<b>Step:3</b>
file [library\think\db\connector\Mysql.php]
namespace think\db\connector;
use PDO;
use think\db\Connection;
class Mysql extends Connection
{
function parseDsn()
{
//mysql 驅(qū)動(dòng)的連接pdo dsn
……
}
}
file [library\think\db\Connection.php]
use PDO;
use PDOStatement;
use think\db\Query;
abstract class Connection
{
protected $PDOStatement; //pdo
protected $query = []; //Query對(duì)象
protected $config = []; //數(shù)據(jù)庫(kù)連接配置
protected $params = [……]; //pdo 相關(guān)設(shè)置
/*
讀取數(shù)據(jù)庫(kù)配置信息
@param$config 數(shù)據(jù)庫(kù)配置數(shù)組
*/
function __construct(array $config = [])
{
if (!empty($config)) {
$this->config = array_merge($this->config, $config);
}
}
function __call($method, $args)
{
//實(shí)例化查詢器(其實(shí)就是查詢、執(zhí)行類)
$this->query['database'] = new Query($this);
/*
$method 方法; $args 參數(shù)
例如:Db::name('table') 那么執(zhí)行Query類name('table')
*/
return call_user_func_array([$this->query['database'], $method], $args);
}
/*
子類實(shí)現(xiàn) abstract
*/
abstract protected function parseDsn($config);
/*
連接數(shù)據(jù)庫(kù)
@param $config 連接參數(shù)
@param $linkNum 連接序號(hào)
@param $autoConnection 是否自動(dòng)連接主數(shù)據(jù)庫(kù)(用于分布式)
return PDO
*/
function connect(array $config = [], $linkNum = 0, $autoConnection = false)
{
if (!isset($this->links[$linkNum])) {
$config = empty($config) ? $this->config : $config;
//pdo的配置參數(shù)
$params = $this->params;
//設(shè)置默認(rèn)返回內(nèi)容類型 array、object、json等
$this->resultSetType = $config['resultset_type'];
try {
$config['dsn'] = $this->parseDsn($config);
//pdo實(shí)例化
$this->links[$linkNum] = new PDO($config['dsn'], $config['username'], $config['password'], $params);
} catch (\PDOException $e) {
……
}
}
return $this->links[$linkNum];
}
function __destruct()
{
// 釋放查詢
if ($this->PDOStatement) {
$this->free();
}
// 關(guān)閉連接
$this->close();
}
/*
參照流程圖:[other_connection_do]
@param $sql sql指令
@param $bind 參數(shù)綁定
@param $master 是否在主服務(wù)器讀操作
@param $class 指定返回的數(shù)據(jù)集對(duì)象
return 數(shù)據(jù)資源
*/
function query($sql, $bind = [], $master = false, $class = false)
{
//初始化數(shù)據(jù)庫(kù)連接
$this->initConnect($master);
//sql bind
$this->queryStr = $this->getRealSql($sql, $bind);
try {
//預(yù)處理 也不知道怎么解釋 參考pdo官方文檔
$this->PDOStatement = $this->linkID->prepare($sql);
// 參數(shù)綁定操作
$this->bindValue($bind);
//執(zhí)行啊
$result = $this->PDOStatement->execute();
//獲取資源數(shù)據(jù)
return $this->getResult($class, $procedure);
} catch {
//GG PDOException
}
}
}
<b>Step:4</b>
file [library\think\db\builder/Mysql.php]
namespace think\db\builder;
use think\db\Builder;
class Mysql extends Builder
{
protected $updateSql = 'UPDATE %TABLE% %JOIN% SET %SET% %WHERE% %ORDER%%LIMIT% %LOCK%%COMMENT%';
/*
字段表名處理
*/
function parseKey($key)
{
……
}
}
file [library\think\db\Builder.php]
namespace think\db;
use think\Db;
use think\db\Connection;
use think\db\Query;
use PDO;
abstract class Builder
{
protected $connection; // connection對(duì)象實(shí)例
protected $query; // 查詢對(duì)象實(shí)例
protected $options = []; // 查詢參數(shù)
//sql表達(dá)式
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%FORCE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%LOCK%%COMMENT%';
protected $insertSql = '……';
protected $insertAllSql = '……';
protected $updateSql = '……';
protected $deleteSql = '……';
/*
數(shù)據(jù)庫(kù)連接對(duì)象實(shí)例
*/
function __construct(Connection $connection)
{
$this->connection = $connection;
}
/*
Query對(duì)象實(shí)例
*/
function setQuery(Query $query)
{
$this->query = $query;
}
/*
參照流程圖:[other_builder_do]
生成查詢sql
@param $options 表達(dá)式
return sql string
*/
function select($options = [])
{
$sql = str_replace(
['%TABLE%', '%DISTINCT%', '%FIELD%', '%JOIN%','%WHERE%'……],
[ $this->parseTable($options['table']),
$this->parseDistinct($options['distinct']),
$this->parseField($options['field']),
$this->parseJoin($options['join']),
$this->parseWhere($options['where'], $options),
……
],
$this->selectSql
);
}
}
<b>Query_do[見(jiàn)流程圖]</b>
abstract class Connection
{
……
/*
參照流程圖:[other_query_do]
數(shù)據(jù)執(zhí)行、查詢動(dòng)作
@param array|string|Query|\Closure $data
return PDOStatement
*/
function select($data = null)
{
$options = $this->parseExpress();
//Step4 獲取sql
$sql = $this->builder()->select($options);
/*
Step5 最終根據(jù)驅(qū)動(dòng)綁定合適的query sqlstring
如果設(shè)置了fetch_sql 則直接去連接器解析綁定sqlstring 直接輸出 測(cè)試用
*/
if ($options['fetch_sql']) {
return $this->connection->getRealSql($sql, $this->bind);
}
/*
Step5 最終根據(jù)驅(qū)動(dòng)綁定合適的query sqlstring
返回 前面有設(shè)置返回類型的
*/
$resultSet = $this->connection->query($sql, $this->getBind(), $options['master'], $options['fetch_class']);
/*
Step6
返回 前面有設(shè)置pdo返回?cái)?shù)據(jù)類型 object or array ……
*/
if ($resultSet instanceof \PDOStatement) {
return $resultSet;
}
}
}