THINKPHP5 Source code parsing (1) database

Source: Internet
Author: User

Objective

TP5 database operations are all done through the DB class, more in line with people's habits, such as simple Db::query (), Db::execute (), and complex chain Operation Db::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:

classdb{    Private Static $instance= [];    Private Static functionParseconfig ($config)    {        if(Empty($config)) {            $config= Config::get (' database '); } Else {            $config= Config::get ($config); }        return $config; }         Public Static functionConnect$config= [])    {        $name=MD5(Serialize($config)); if(!isset(Self::$instance[$name])) {            $options= self::p arseconfig ($config); Self::$instance[$name] =New\think\db\connector\Mysql($options); }        returnSelf::$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:

<?PHPAbstract classconnection{    protected $PDOStatement;    protected $linkID;    protected $config= [];  Public function__construct (Array $config= [])    {        if(!Empty($config)) {            $this->config =Array_merge($this->config,$config); }    }    protected functionGetResult () {return $this->pdostatement->fetchall (PDO::FETCH_ASSOC); }        protected functionBindvalue (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 functionConnect () {if(!$this-LinkID) {            $config=$this-config; $this->linkid =NewPDO ($config[' DSN '],$config[' username '],$config[' Password ']); }        return $this-LinkID; }             Public functionQuery$sql,$bind= [])    {        $this-Connect (); if(Empty($this-pdostatement)) {            $this->pdostatement =$this->linkid->prepare ($sql); }                $this->bindvalue ($bind); $this->pdostatement->execute (); return $this-GetResult (); }    }

It's clear that connection defines query (), which calls connect () executes the PDO driver connection database, then data binding, and finally gets the query results

Conclusion

DB does not implement query (), it is only responsible for instantiating the corresponding database driver, through the __callstatic () Magic method call Connection query (), UML class diagram representation:

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 () {    returnnew \think\db\query ($this);}  Public function __call ($method$args) {    returncall_user_ Func_array([$this$method$args);}

So db::table (' user ') actually triggers the __call () Magic method, then instantiates a Think\db\query object (the constructor passes in the current Think\db\connector\mysql object), See what the query does:

namespace Think\db;classquery{protected $connection; protected $builder;  Public function__construct (Connection$connection)    {        $this->connection =$connection; $this-Setbuilder (); }        protected functionSetbuilder () {$this->builder =New\think\db\builder\Mysql($this->connection,$this); }         Public functionTable$table)    {        $this->options[' table '] =$table; return $this; }         Public functionwhere$where)    {        $this->options[' where '] =$where; return $this; }         Public functionQuery$sql)    {        return $this->connection->query ($sql); }         Public functionSelect)    {        $options=$this-options; $this->options = []; $sql=$this->builder->select ($options);return $this->query ($sql); }}

The constructor first saves the current Think\db\connector\mysql 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 Think\db\builder\mysql->select () to get the assembled SQL, by the connection->query () query database to obtain the result set, the entire process to this end, then think\db\ How does builder\mysql assemble SQL?

namespace Think\db\builder; class Mysql extends builder{    protectedfunction  parserand ()    {        return ' Rand () ';    }}

The Select () is not defined, but it inherits the builder and looks at the builder code:

namespace Think\db;Abstract classbuilder{protected $connection; protected $query; protected $SELECTSQL= ' SELECT%field% from%table%%where% ';  Public functionSelect$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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.