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