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 協議》,轉載必須註明作者和本文連結