ThinkPHP5源碼分析之Db(5.1)

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;
    }
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容