2.2 - Laravel - 5.6 - Facade - 关于 facade 加载
larave在启动的时候会预先加载facade 已经配置好的映射。以便在后面facade调用的时候使用。
启动流程是这样的
1.起始页面 index.php 加载了$app = require_once __DIR__.'/../bootstrap/app.php';
2.在bootstrap/app.php中加载
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
3.然后在 App\Http\Kernel::class
的父类中
加载了
protected $bootstrappers = [
...
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
...
];
4.这个RegisterFacades::class 就是facade预加载的核心类,只有一个bootstrap方法:
public function bootstrap(Application $app)
{
//1 第一步
Facade::clearResolvedInstances();
//2 第二步
Facade::setFacadeApplication($app);
//3 第三步
AliasLoader::getInstance(array_merge(
$app->make('config')->get('app.aliases', []),
$app->make(PackageManifest::class)->aliases()
))->register();
}
bootstrap方法做了如下的事情:
1.清空对象类数组实例
1.1 清空处理就是置空。
public static function clearResolvedInstances()
{
static::$resolvedInstance = [];
}
2.把容器放入facade对象,就是facade中的set方法
在2.1 上一章的abstract class Facade
中,我们使用setFacadeApplication
方法来注入容器对象(app)给facade类。
public static function setFacadeApplication($app)
{
static::$app = $app;
}
3.把facade对象从config中读取后注册(这个注册就是建立关系)
3.1 获取所有配置的facade对应关系
$app->make('config')->get('app.aliases', []),
$app->make(PackageManifest::class)->aliases()
默认的别名配置是从 app 配置文件下的 aliases数组 读取的,PackageManifest 是 laravel 5.5 新增的 包自动发现规则,这里我们暂时不考虑,还没研究。
3.2 使用AliasLoader的getInstance方法注册这些对应关系。
public static function getInstance(array $aliases = [])
{
if (is_null(static::$instance)) {
return static::$instance = new static($aliases);
}
$aliases = array_merge(static::$instance->getAliases(), $aliases);
static::$instance->setAliases($aliases);
return static::$instance;
}
3.2.1 第一步 如果当前这个实例为空,重新生成一个
3.2.2 把当前已经有的alias(别名)和传入的alias合并
3.2.3 返回当前这个AliasLoader实例,包含了所有该有的别名映射。
3.3 使用 register()方法注册
public function register()
{
if (! $this->registered) {
$this->prependToLoaderStack();
$this->registered = true;
}
}
3.3.1 prependToLoaderStack
函数通过使用php自动加载方法spl_autoload_register
把当前对象(当前AliasLoader类中有个load方法)的load方法 放到SPL __autoload
函数队列的头部。如果php运行中触发了没有声明的类,会自动运行load这个函数。load函数通常都要引入(require 或者include)需要的类,如果没有,就会在队列中继续寻找需要的类。(详细部分放在下一章 2.3)
protected function prependToLoaderStack()
{
spl_autoload_register([$this, 'load'], true, true);
}
3.3.1.1 然后看下这个load函数,主要存在两种情况。
public function load($alias)
{
if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
$this->loadFacade($alias);
return true;
}
if (isset($this->aliases[$alias])) {
return class_alias($this->aliases[$alias], $alias);
}
}
a.判断facade的别名中是否存在启始位置为Facades\\
的字段, 如果有就要调用loadFacade()
去加载。
b.如果没有,这里是核心方法,使用了php的class_alias方法把别名和真实的类建立关系
比如我们直接使用
Route
时, 我们其实是调用的Illuminate\Support\Facades\Route类。
说到底,这个整个第三步其实就是使用了class_alias
给配置项产生一个别名。然后存起来
本作品采用《CC 协议》,转载必须注明作者和本文链接