2.1 - Laravel - 5.6 - Facade - 解析機制

HarveyNorman發表於2020-07-13

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

相關文章