Facades
介紹
Facades 提供一個靜態介面讓類別可以在應用程式的 IoC 容器 裡運用。Laravel 附帶許多 facades,甚至你可能已經在使用它們即使你並不知道!Laravel 的「facades」在 IoC 容器裡面作為的基底類別的靜態代理,提供有簡潔、易表達優點的語法,同時維持比傳統的靜態方法更高的可測試性和彈性。
你偶爾或許會希望為你的應用程式和套件建立自己的 facades,所以讓我們來探索這些類別的概念、開發和用法。
備註: 在深入 facades 之前,強烈建議你先熟悉 Laravel IoC 容器。
解釋
在 Laravel 應用程式的環境中,facade 是個提供從容器存取物件的類別。使這個機制可以運作的原因在 Facade 類別中。Laravel 的 facades 和任何你建立的客製化 facades,將會繼承基本的 Facade 類別。
你的 facade 類別只需要去實作一個方法:getFacadeAccessor。getFacadeAccessor 方法的工作是定義要從容器解析什麼。基本的 Facade 類別利用 __callStatic() 魔術方法去從你的 facade 呼叫到解析物件。
所以當你對 facade 呼叫,例如 Cache::get,Laravel 從 IoC 容器解析快取管理類別出來,並對類別呼叫 get 方法。用科技術語來說,Laravel Facades 是使用 Laravel IoC 容器作為服務定位器的便捷語法。
實際用法
在下面的例子,對 Laravel 快取系統進行呼叫。簡單看過這程式碼,有人可能會以為靜態方法 get 是被 Cache 類別呼叫。
$value = Cache::get('key');然而,如果我們去看 Illuminate\Support\Facades\Cache 類別,你將會看到他沒有靜態方法 get:
class Cache extends Facade {
    /**
     * Get the registered name of the component.
     *
     * @return string
     */
    protected static function getFacadeAccessor() { return 'cache'; }
}Cache 類別繼承基本的 Facade 類別並定義方法 getFacadeAccessor()。記住,這個方法的工作是回傳 IoC 綁定的名稱。
當使用者參考 Cache facade 的任何靜態方法,Laravel 會從 IoC 容器解析被綁定 cache,並對該物件執行被請求的方法 (在這個例子,get)。
所以我們的 Cache::get 呼叫可以被重寫成這樣:
$value = $app->make('cache')->get('key');建立 Facades
為你的應用程式或套件建立 facade 是很簡單的。你只需要 3 個東西:
- 一個 IoC 綁定。
- 一個 facade 類別。
- 一個 facade 別名設定。
讓我們來看個例子。這裡我們有一個定義為 PaymentGateway\Payment 的類別。
namespace PaymentGateway;
class Payment {
    public function process()
    {
        //
    }
}這個類別可以存在在你的 app/models 資料夾,或者任何其他 Composer 知道如何自動載入的資料夾。
我們需要可以從 IoC 容器解析出這個類別。所以,讓我們來加個綁定:
App::bind('payment', function()
{
    return new \PaymentGateway\Payment;
});註冊這個綁定的好方式是建立新的 服務提供者 命名為 PaymentServiceProvider,並把這個綁定加到 register 方法。再來你可以從 app/config/app.php 檔案設定讓 Laravel 載入你的服務提供者。
接下來,我們可以建立我們自己的 facade 類別:
use Illuminate\Support\Facades\Facade;
class Payment extends Facade {
    protected static function getFacadeAccessor() { return 'payment'; }
}最後,如果我們希望,我們可以在 app/config/app.php 設定檔案為我們的 facade 加個別名到 aliases 陣列。現在我們可以對 Payment 類別的實體呼叫 process 方法。
Payment::process();自動載入別名的附註
在 aliases 陣列中的類別在某些實體中不能使用,因為 PHP 將不會嘗試去自動載入未定義的類型暗示類別。如果 \ServiceWrapper\ApiTimeoutException 命別名為 ApiTimeoutException,即便有例外被拋出,在 \ServiceWrapper 命名空間外面的 catch(ApiTimeoutException $e) 將永遠捕捉不到例外。類似的問題在有類型暗示的別名類別模型一樣會發生。 唯一的解決辦法就是放棄別名並用 use 在每一個檔案的最上面引入你希望暗示類型的類別。
模擬 Facades
單元測試是為什麼現在 facades 採用這樣的工作方式的重要面向。事實上,可測試性甚至是 facades 存在的主要理由。想要獲得更多資訊,請查看文件的 mocking facades 部分。
Facade 類別參考
你將會在下面找到每一個 facade 和它的基底類別。這是個可以從一個給定的 facade 根源快速地深入 API 文件的有用工具。可應用的 IoC 綁定 關鍵字也包含在裡面。