Objective
TP5 database operations are all done through the DB class, more in line with the habits of the people, such as Simple db::query (),Db::execute (), and complex chain Operation db::table (' user ')- >where (' id=1 ')->select (), the following is the source to understand its work flow
Before looking at the code, let's look at what classes are involved, and TP5 database-related classes have the following:
Db (User interface)
Connection (connector)
Query (Finder)
Builder (SQL Builder)
Db::query () What happened? Assuming that the configuration file settings are driven to MySQL, how does the TP5 database class work when the following code is executed?
Db::query ("SELECT * from user where id=?", [1]);
To save the chapters and better understand the process, just the core code is shown below, some of the code is simplified or modified, let's take a look at the DB class:
class db{ private static $instance = []; private static function parseconfig ($config) { if (Empty ($config)) { $config = config::get (' database '); } else { $config = config::get ($config); } return $config; } public static function connect ($config = []) {$name  = MD5 (Serialize ($config)); if (!isset (self::$ instance[$name]) {$options &Nbsp;= self::p arseconfig ($config); Self:: $instance [$name] = new \think\db\connector\mysql ($ options); } return self:: $instance [ $name]; } public static function __callstatic ($ method, $params) {return call_user_func_array ([Self::connect (), $method] , $params); }}
Because the DB class does not define query (), it triggers __callstatic (), __callstatic () and calls its own connect (), connect () instantiates the MySQL connector (incoming database configuration $options), and then saves to $instance (an array of database connection instances), and then look at the MySQL connector:
namespace Think\db\connector;class Mysql extends connection{protected $builder = ' \\think\\db\\builder\\Mysql '; }
MySQL connector also does not define query () Yes, it inherits connection and see if connection has:
abstract class connection{ protected $ pdostatement; protected $linkID; protected $config = []; public function __construct (array $config = [ ]) { if (!empty ($config)) { $this->config = array_ Merge ($this->config, $config); } } protected function getresult () { return $this->pdostatement->fetchall (PDO::FETCH_ASSOC); } protected function bindvalue ( array $bind = []) { foreach ($bind as $key => $val) { $param = Is_numeric ($key) ? $key + 1 : ': ' . $key; if (Is_array ($val)) { if (PDO::P aram_int == $val [1] && " === $val [0]) { $val [0] = 0; } $result = $this->pdostatement- >bindvalue ($param, $val [0], $val [1]); } else { $result = $this->pdostatement->bindvalue ($param, $val); } } } public function connect () { if (! $this->linkid) { $config = $this->config; $this->linkid = new pdo ($config [' DSN '], $config [' username '], $config [' Password ']); } return $this->linkid; } public function query ($sql, $bind = []) { $this->connect (); if (Empty ($this->pdostatement)) { $this->pdostatement = $this->linkid->prepare ($sql); } $this->bindvalue ($bind); $this->pdostatement->execute (); return $this- >getresult (); } }
Conclusion
Db::query () triggers db::__callstatic (), instantiates the MySQL connector and calls Mysql->query (), and the MySQL connector inherits connection, so it is actually called connection- >query ()
What happened to db::table (' user ')->where (' id=1 ')->select ()?
Both DB and MySQL connectors do not have a table () method defined, and connection also has a __call ():
protected function Getquery () {return new \think\db\query ($this);} Public Function __call ($method, $args) {return Call_user_func_array ([$this->getquery (), $method], $args);}
So db::table (' user ') actually triggered the __call () Magic method, and then instantiated a query object (the constructor passed in to the current MySQL connector object) to see what the query was doing:
namespace think\db;class query{ protected $connection; protected $builder; public function __ Construct (connection $connection) { $this->connection = $connection; $this Setbuilder (); } protected function setbuilder () { $this->builder = new \think\db\builder\mysql ($this->connection, $this); } public function table ($table) { $this->options[' table '] = $table; return $this; } public Function where ($where) { $this options[' where '] = $where; return $this; } public function query ($sql) { return $this->connection->query ( $sql); } public function Select () { $options = $this- >options; $this->options = []; $sql = $this->builder->select ($options);return $this- >query ($sql); }}
The constructor first saves the current Mysql connector object and instantiates the Think\db\builder\mysql
Query->table () Saves the table name to the $options array, and then returns $this (the current instance) for a chained operation, where () again, focus on select (), it gets $options and empties it for next use, Then call the Builder->select () to get the assembled SQL, by the Connection->query () query the database to obtain the result set, the entire process to this end, then builder is how to assemble SQL?
namespace Think\db\builder;class Mysql extends builder{protected function Parserand () {return ' rand () '; }}
think\db\builder\mysql does not define select (), but it inherits from builder and looks at the builder code:
namespace think\db;abstract class builder{ protected $connection; protected $query; protected $selectSql = ' select %field% from %table% %where% '; public function select ($options = []) { $sql = str_replace ( ['%table% ', '%field% ', '%where% '], [ $options [' table '], $options [' field '] ?: ' * ', $options [' where '] ? ' where '. $options [' WHERE '] : ', ], $this->selectsql); return $sql; } }
Builder replaces SQL templates with $options to get SQL
Conclusion
Db::table () triggers the __callstatic () Instantiation connection and invokes table (), because connection also does not define table (), and it triggers its own __call () instantiation of query and calls table () , table () returns $this to implement the chained Operation Db::table ()->where ()->select (), and select calls Builder->select () to get SQL, and finally calls connection- >query () Gets the result of the query, the solid complete class diagram is represented as follows:
THINKPHP5 Source code parsing (1) database