laravel核心构架——DB Facade

laravel核心构架——DB Facade

    • 结论
    • 使用原理
      • DB类:
      • Facade类
      • DatabaseManager 类
      • MySqlConnection类

laravel中文文档中数据库查询构造器中介绍了使用DB的静态接口的方式进行数据库查询,文档中的示例使用了 DB::table("...");DB::raw("...");等,那么DB Facade除此之外还有哪些接口呢?

结论

为了节约时间,先说结果:DB Facede可使用的接口参考Illuminate\Database\MySqlConnection类,API文档:Illuminate\Database\MySqlConnection | Laravel API

使用原理

DB类:

// vendor/laravel/framework/src/Illuminate/Support/Facades/DB.php

namespace Illuminate\Support\Facades;

/**
 * @see \Illuminate\Database\DatabaseManager
 * @see \Illuminate\Database\Connection
 */
class DB extends Facade
{
     
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
     
        return 'db';
    }
}

DB类非常简单,并没有table()等静态方法,那么只能在DB的父类Facade中找答案:

// // vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php

namespace Illuminate\Support\Facades;

use Mockery;
use RuntimeException;
use Mockery\MockInterface;

abstract class Facade
{
     
	...
}

Facade类

Facade是一个抽象类,Facade类有个一个重要的魔术方法__callStatic($method, $args),当我们调用DB的静态方法时,就会执行这个魔术方法。

// Illuminate\Support\Facades\Facade


/**
 * Handle dynamic, static calls to the object.
  *
  * @param  string  $method
  * @param  array   $args
  * @return mixed
  *
  * @throws \RuntimeException
  */
 public static function __callStatic($method, $args)
 {
     
     $instance = static::getFacadeRoot();

     if (! $instance) {
     
         throw new RuntimeException('A facade root has not been set.');
     }

     return $instance->$method(...$args);
 }

这个方法中,通过$instance->$method(...$args);的方式调用我们使用的静态方法(更多关于__callStatic的信息参见:PHP: 重载 - Manual)。
$instance对象通过getFacadeRoot()静态方法获得:


/**
 * Get the root object behind the facade.
 *
 * @return mixed
 */
public static function getFacadeRoot()
{
     
    return static::resolveFacadeInstance(static::getFacadeAccessor());
}

/**
 * Resolve the facade root instance from the container.
 *
 * @param  string|object  $name
 * @return mixed
 */
protected static function resolveFacadeInstance($name)
{
     
    if (is_object($name)) {
     
        return $name;
    }

    if (isset(static::$resolvedInstance[$name])) {
     
        return static::$resolvedInstance[$name];
    }

    return static::$resolvedInstance[$name] = static::$app[$name];
}

getFacade方法调用了resolveFacadeInstance($name)方法,而参数就是DB::getFacadeAccessor()返回的字符串"db",最终在返回$app[$name]$app应该就是laravel的Appliaction对象。我在控制台中进行检验:
laravel核心构架——DB Facade_第1张图片
看到$instance是一个Illuminate\Database\DatabaseManager的实例。这也与laravel中文文档中对Facade的原理介绍一致(Facades |《Laravel 5.5 中文文档 5.5》| Laravel China 社区)。

DatabaseManager 类

DatabaseManager类中定义了_call魔术方法:

// vendor/laravel/framework/src/Illuminate/Databases/DatabaseManager.php

namespace Illuminate\Database;

use PDO;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Database\Connectors\ConnectionFactory;

/**
 * @mixin \Illuminate\Database\Connection
 */
class DatabaseManager implements ConnectionResolverInterface
{
     
	...
	
	    /**
     * Dynamically pass methods to the default connection.
     *
     * @param  string  $method
     * @param  array   $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
     
        return $this->connection()->$method(...$parameters);
    }
}

我们调用connection()方法来查看调用方法的对象:
connection

MySqlConnection类

最终就是MySqlConnection类的实例:

// vendor/laravel/framework/src/Illuminate/Databases/MySqlConnection.php

namespace Illuminate\Database;

use PDO;
use Illuminate\Database\Schema\MySqlBuilder;
use Illuminate\Database\Query\Processors\MySqlProcessor;
use Doctrine\DBAL\Driver\PDOMySql\Driver as DoctrineDriver;
use Illuminate\Database\Query\Grammars\MySqlGrammar as QueryGrammar;
use Illuminate\Database\Schema\Grammars\MySqlGrammar as SchemaGrammar;

class MySqlConnection extends Connection
{
     
	...
}

虽然MySqlConnection类中并没有定义我们调用的方法,但父类中Connection中有定义:

// vendor/laravel/framework/src/Illuminate/Databases/Connection.php

namespace Illuminate\Database;

class Connection implements ConnectionInterface
{
     
	...
    /**
     * Begin a fluent query against a database table.
     *
     * @param  string  $table
     * @return \Illuminate\Database\Query\Builder
     */
    public function table($table)
    {
     
        return $this->query()->from($table);
    }
    /**
     * Get a new query builder instance.
     *
     * @return \Illuminate\Database\Query\Builder
     */
    public function query()
    {
     
        return new QueryBuilder(
            $this, $this->getQueryGrammar(), $this->getPostProcessor()
        );
    }

    /**
     * Run a select statement and return a single result.
     *
     * @param  string  $query
     * @param  array   $bindings
     * @param  bool  $useReadPdo
     * @return mixed
     */
    public function selectOne($query, $bindings = [], $useReadPdo = true)
    {
     
        $records = $this->select($query, $bindings, $useReadPdo);

        return array_shift($records);
    }
	
	...
}

你可能感兴趣的:(laravel,php,laravel)