Illuminte\Foundation\Bootstrap\RegisterFacades.php
public function bootstrap(Application $app)
{
Facade::clearResovedInstances();
Facade::setFacadeApplication($app);
AliasLoader::getInstance($app->make('config')->get('app.aliases'))->register();
}
Illuminate\Foundation\AliasLoader.php
// 外觀別名類陣列
protected $aliases;
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;
}
public function register()
{
if(!$this->registered){
$this->prependToLoaderStack();
$this->registered = true;
}
}
public function prependToLoaderStack()
{
spl_autoload_register([$this, 'load'], true, true);
}
public function load($alias)
{
if(isset($this->aliases[$alias])){
class_alias($this->aliases[$alias], $alias);
}
}
class_alias ( string $original , string $alias [, bool $autoload = TRUE ] ) : bool。為一個類建立別名。比如給Illuminate\Support\Facades\Route類起個Route的別名,class_alias('Illuminate\Support\Facades\Route', 'Route')這樣就行了。這麼做的好處是根域名中的Route就表示名稱空間為Illuminate\Support\Facades的Route類。
外觀註冊是通過RegisterFacades類的bootstrap()函式實現的。實現門面類其實分為兩個步驟。1.是例項話外觀自動載入類Illuminate\Foundation\Aliasloader::class並把外觀別名陣列新增到該例項中,。2.完成自動載入類中的自動載入函式的新增。用getInstance()單例模式例項話外觀自動載入類。再用$app->make('config')->get('app.aliases')來獲取外觀類陣列。這句程式碼就用到了配置載入的內容,即獲取載入的app.php的配置檔案,返回陣列的鍵為”aliases”的陣列值。
在自動載入類例項話以後,會呼叫register()函式向自動載入棧的開始處加入一個新的載入函式,即通過程式碼spl_autoload_register([$this, 'load'], true, true)實現。所有類的自動載入都先經過這個函式。這個函式就是AliasLoader類例項的load()函式。此函式的作用是為外觀類設定一個別名。即外觀別名,當使用者通過外觀別名訪問類時,實際上訪問的是對應的外觀類。下面我們就看看通過外觀別名怎實現類似Route::get('路徑','響應函式')這樣的函式呼叫。
首先程式會呼叫Route類,由於註冊了外觀別名。那麼會自動載入第一個函式是AliasLoader類的load()函式。該函式會查詢別名對應類。於是便找到Route的外觀別名是Illuminate\Support\Facades\Route類,並載入這個類接著呼叫該類的get()靜態函式。可是這個類沒有對應的函式。不過它繼承了Illuminate\Support\Facades\Facade這個類。該類也沒有對應的靜態函式,不過該類有__callstatic()函式。這個函式是在沒有查詢到對應的靜態函式時候會被呼叫。__callstatic()函式裡面有個$instance = static::getFacadeRoot()來獲取對應類的例項,其中getFacadeRoot()靜態函式是根據Illuminate\Support\Facades\Route類的getFacadeAccessor()函式來例項話對應的Route類例項。最後呼叫Route例項的get函式,流程完畢。下面是相應的程式碼。
Illuminate\Support\Facades\Facade.php
public function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
public function resolveFacadeInstance($name)
{
// 這裡不用看
if(is_object($name)){
return $name;
}
if(isset(static::resolvedInstance[$name])){
return static::resolvedInstance[$name];
}
// 主要看這裡,static::$app[$name]這個是以陣列的形式例項話類。等同於,$app->make($name);
return static::$resolvedInstance[$name] = static::$app[$name]
}
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
// return call_user_func_array([$instance, $method], $args);
return $instance->$method(...$args);
}