Facades 门面
app.php 中$app->withFacades()开启门面模式就可以使用DB类
public function withFacades($aliases = true, $userAliases = [])
{
Facade::setFacadeApplication($this);
if ($aliases) {
$this->withAliases($userAliases);
}
}
\Illuminate\Support\Facades\Facade::setFacadeApplication
可以看出,其实就是把app对象赋值给Facade类的app属性,而在Application实例话,启动容器的时候已经把db作为别名注入进去了,\Laravel\Lumen\Application::registerContainerAliases
然后在使用DB类调用数据库函数的时候其实就是使用app对象app['db']这样调用数据库。
DB类实现Facade的一个方法,返回的就是一个数据库类的别名\Illuminate\Support\Facades\DB::getFacadeAccessor
例如:
DB::select('SELECT *FROM users WHERE 1 LIMIT 1')
其实就是调用Facades类的__callStatic方法,__callStatic方法里\Illuminate\Support\Facades\Facade::getFacadeRoot获取一个db对象,然后调用相应的方法,把查询的参数传进去。
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);
}
db别名绑定的是Illuminate\Database\DatabaseManager这个数据库管理类,这个类是一个公共类,同时支持其他数据库驱动,如'mysql', 'pgsql', 'sqlite', 'sqlsrv',默认在config.php配置的是mysql,在查询的时候就指的是mysql的驱动,如select查询调用DatabaseManager类的call方法,如果没有指定connections,会取默认的数据库连接,比如不同数据库之间的查询,由config文件的database.default这个控制,根据数据库名称从configure里面取出一个链接的配置类容。那么db是在什么时候注册进去的呢,这个其实只是在一开始做类一个绑定,在应用的时候通过make方法取出一个实例来。
protected function registerContainerAliases()
{
$this->aliases = [
'Illuminate\Database\DatabaseManager' => 'db',
];
}
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($abstract);
if (array_key_exists($abstract, $this->availableBindings) &&
! array_key_exists($this->availableBindings[$abstract], $this->ranServiceBinders)) {
$this->{$method = $this->availableBindings[$abstract]}();
$this->ranServiceBinders[$method] = true;
}
return parent::make($abstract, $parameters);
}
/**
* The available container bindings and their respective load methods.
*
* @var array
*/
public $availableBindings = [
'db' => 'registerDatabaseBindings',
];
protected function registerDatabaseBindings()
{
$this->singleton('db', function () {
return $this->loadComponent(
'database', [
'Illuminate\Database\DatabaseServiceProvider',
'Illuminate\Pagination\PaginationServiceProvider',
], 'db'
);
});
}
/**
* \Illuminate\Database\DatabaseServiceProvider::registerConnectionServices
* Register the primary database bindings.
*
* @return void
*/
protected function registerConnectionServices()
{
// The connection factory is used to create the actual connection instances on
// the database. We will inject the factory into the manager so that it may
// make the connections while they are actually needed and not of before.
$this->app->singleton('db.factory', function ($app) {
return new ConnectionFactory($app);
});
// The database manager is used to resolve various connections, since multiple
// connections might be managed. It also implements the connection resolver
// interface which may be used by other components requiring connections.
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
$this->app->bind('db.connection', function ($app) {
return $app['db']->connection();
});
}
DatabaseManager这里调用call方法的时候会去获取默认的connection,\Illuminate\Database\DatabaseManager::makeConnection这个方法就是为了获取一个数据库连接的实例,config, $name) 这里的factory就是ConnectionFactory类,调用它里面的make方法,参数就是数据库的配置数组,和名称,这里就是名称就是mysql,\Illuminate\Database\Connectors\ConnectionFactory::createConnection个方法就是去连接数据库了,MySqlConnection继承了\Illuminate\Database\Connection这个类,调用它的select方法执行sql。ConnectionFactory是一个生产连接的工厂类,\Illuminate\Database\ConnectionInterface这个接口在\Illuminate\Database\Connection基础类上实现了它,然后不同的数据库驱动又继承了基础的connection类。
ORM 对象关系模型
app.php 中$app->withEloquent()开启orm关系模式
和门面一样,在app对象实例化的时候已经绑定了db的别名,开启orm的时候通过make方法取出数据库的实例,db就是在make的时候去寻找系统已经绑定的数组,注入容器,运行加载的方法,比如db就是这个\Laravel\Lumen\Application::registerDatabaseBindings方法,这个方法里加载了数据库的配置文件以及注册数据库服务,返回一个db的实例。
class DatabaseServiceProvider extends ServiceProvider
{
public function boot()
{
Model::setConnectionResolver($this->app['db']);
Model::setEventDispatcher($this->app['events']);
}
public function register()
{
Model::clearBootedModels();
$this->registerConnectionServices();
$this->registerEloquentFactory();
$this->registerQueueableEntityResolver();
}
protected function registerConnectionServices()
{
$this->app->singleton('db.factory', function ($app) {
return new ConnectionFactory($app);
});
$this->app->singleton('db', function ($app) {
return new DatabaseManager($app, $app['db.factory']);
});
$this->app->bind('db.connection', function ($app) {
return $app['db']->connection();
});
}
protected function registerEloquentFactory()
{
$this->app->singleton(FakerGenerator::class, function ($app) {
return FakerFactory::create($app['config']->get('app.faker_locale', 'en_US'));
});
$this->app->singleton(EloquentFactory::class, function ($app) {
return EloquentFactory::construct(
$app->make(FakerGenerator::class), $this->app->databasePath('factories')
);
});
}
protected function registerQueueableEntityResolver()
{
$this->app->singleton(EntityResolver::class, function () {
return new QueueEntityResolver;
});
}
}
\Illuminate\Database\DatabaseServiceProvider注册的时候运行boot方法,db的实例在这设置给\Illuminate\Database\Eloquent\Model类中,register方法中先清除已启动的实例,接下来就是一系列数据库相关的注册到容器中,应用的时候,我们所有的模型类都会实现\Illuminate\Database\Eloquent\Model,它使用了其他orm操作运算的一些trait类(trait类会覆盖类继承的方法,当前类的中法又会覆盖trait中的方法,这也是php解决单继承做的一个扩展)。
网友评论