Facade解釋
Facade 是一組靜態類介面或者說代理,讓開發者能簡單的訪問繫結到服務容器裡的各種服務。
簡單說就是使用一個靜態類(用一個別名)直接能訪問服務(就是能直接呼叫方法)
以一個路由舉例
Route::get('/','PagesController@root')->name('root');
這裡的Route我們發現找不到這個靜態類
,也沒有路徑,他能這麼用其實是是使用laravel中的別名aliases機制
在檔案config/app.php最下面我們可以看到
aliases的配置。
發現了對應的class.
'Route' => Illuminate\Support\Facades\Route::class,
Facade實現
基本的結構邏輯是這樣的:
1. Facade 有個__callStatic
方法接受所有Facede
未申明的方法。比如這個例子中
Route::get();
這個get方法在Facade中不存在直接會呼叫__callStatic
2. 通過這個魔術方法,尋找在儲存解析後的物件中有沒有一個Route的物件。
3. 找到這個物件觸發這個物件的get方法。
現在我們接著進去看看這個route類,
class Route extends Facade
{
protected static function getFacadeAccessor()
{
return 'router';
}
}
這個類程式碼非常簡單, 只提供了這個方法 getFacadeAccessor()
返回router
字串而已。我們肯定想到,要去父類Facade看看。
父類方法中 $app
是一個容器
protected static $app;
resolvedInstance
是儲存解析出來的Facade對應的服務類例項,這裡Route
真實的類例項就存在這裡。索引陣列,鍵值:Facade名稱;值:服務類例項
protected static $resolvedInstance;
而此方法中並沒有Route::get 對應的get方法, 其實上它call了__callStatic
魔術方法
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);
}
1.這個方法中首先 getFacadeRoot 方法獲取解析的物件
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
1.1 getFacadeRoot()中static::getFacadeAccessor() 我們在子類中已經重寫了返回的是字串 router
1.2 進入resolveFacadeInstance方法看看
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];
}
此方法就是核心方法了:返回真實的route物件。
a.首先他判斷$name是不是一個物件,我們傳入的是字串‘route’,(這樣說來 我們return一個new router()物件似乎也是可以的。)
b.如果不是物件,去$resolvedInstance
陣列中尋找是否存在解析的route物件
c.如果有的話直接返回,如果沒有,再去容器app中取route物件,同時存入resolvedInstance陣列後,再返回,這樣下次resolvedInstance陣列中肯定就有了。
Facade就到這裡獲得了真實的物件。
2.如果這個物件是不存在丟擲異常
3.執行這個物件中的方法 這裡就是get
方法。
$instance->$method(...$args);
關於 static::$app[$name]
- 這個static::$app[$name] 這是怎麼解析的呢。
這裡使用了php的ArrayAccess 預定義介面,具體功能就是一旦實現了這個介面,就能像陣列一樣訪問物件。這裡$app是類Application的一個物件,Application又是Container的子類,Container這個類實現了ArrayAccess介面。就這樣就能像陣列一樣取得對應的物件了。
本作品採用《CC 協議》,轉載必須註明作者和本文連結