Facades 提供一個(gè)靜態(tài)接口給在應(yīng)用程序的 服務(wù)容器 中可以取用的類。Laravel 附帶許多 facades,甚至你可能已經(jīng)在不知情的狀況下使用過(guò)它們!Laravel 的「facades」作為在 IoC 容器里面的基礎(chǔ)類的靜態(tài)代理,提供的語(yǔ)法有簡(jiǎn)潔、易表達(dá)的優(yōu)點(diǎn),同時(shí)維持比傳統(tǒng)的靜態(tài)方法更高的可測(cè)試性和彈性。
有時(shí),你或許會(huì)希望為應(yīng)用程序和擴(kuò)展包建立自己的 facades,所以讓我們來(lái)探索這些類的概念、開(kāi)發(fā)和用法。
注意: 在深入了解 facades 之前,強(qiáng)烈建議你先熟悉 Laravel 服務(wù)容器.
在 Laravel 應(yīng)用程序的環(huán)境中,facade 是個(gè)提供從容器訪問(wèn)對(duì)象的類。Facade
類是讓這個(gè)機(jī)制可以運(yùn)作的原因。Laravel 的 facades 和你建立的任何自定義 facades,將會(huì)繼承基類 Facade
。
你的 facade 類只需要去實(shí)現(xiàn)一個(gè)方法:getFacadeAccessor
。getFacadeAccessor
方法的工作是定義要從容器解析什么?;?Facade
利用 __callStatic()
魔術(shù)方法來(lái)從你的 facade 調(diào)用到解析出來(lái)的對(duì)象。
所以當(dāng)你對(duì) facade 調(diào)用,例如 Cache::get
,Laravel 從服務(wù)容器解析緩存管理類出來(lái),并對(duì)該類調(diào)用 get
方法。用專業(yè)口吻來(lái)說(shuō),Laravel Facades 是使用 Laravel 服務(wù)容器作為服務(wù)定位器的便捷語(yǔ)法。
在下面的例子,對(duì) Laravel 緩存系統(tǒng)進(jìn)行調(diào)用。簡(jiǎn)單看過(guò)去這代碼,有人可能會(huì)以為靜態(tài)方法 get
是對(duì) Cache
類調(diào)用。
$value = Cache::get('key');
然而,如果我們?nèi)タ?Illuminate\Support\Facades\Cache
類,你將會(huì)看到它沒(méi)有靜態(tài)方法 get
:
class Cache extends Facade { /** * 取得組件的注冊(cè)名稱 * * @return string */ protected static function getFacadeAccessor() { return 'cache'; }}
Cache 類繼承基類 Facade
并定義一個(gè) getFacadeAccessor()
方法。記住,這個(gè)方法的工作是返回服務(wù)容器綁定的名稱。
當(dāng)用戶在 Cache
的 facade 上參考任何的靜態(tài)方法,Laravel 會(huì)從服務(wù)容器解析被綁定的 cache
,并對(duì)該對(duì)象執(zhí)行被請(qǐng)求的方法 (在這個(gè)例子中, get
)。
所以我們的 Cache::get
調(diào)用可以被重寫成像這樣:
$value = $app->make('cache')->get('key');
記住,如果你在控制器有使用命名空間的情況下使用 facade,你會(huì)需要導(dǎo)入 facade 類進(jìn)入命名空間。所有的 facades 存在于全局命名空間:
<?php namespace App\Http\Controllers;use Cache;class PhotosController extends Controller { /** * 取得所有的應(yīng)用程序相片。 * * @return Response */ public function index() { $photos = Cache::get('photos'); // }}
為你自己的應(yīng)用程序或擴(kuò)展包建立 facade 是很簡(jiǎn)單的。你只需要 3 個(gè)東西:
一個(gè)服務(wù)容器綁定。
一個(gè) facade 類。
一個(gè) facade 別名配置。
讓我們來(lái)看個(gè)例子。這里有一個(gè)定義為 PaymentGateway\Payment
的類。
namespace PaymentGateway;class Payment { public function process() { // }}
我們需要可以從服務(wù)容器解析出這個(gè)類。所以,讓我們來(lái)加上一個(gè)綁定到服務(wù)提供者:
App::bind('payment', function(){ return new \PaymentGateway\Payment;});
注冊(cè)這個(gè)綁定的好方式是建立新的 服務(wù)提供者 命名為 PaymentServiceProvider
,并把這個(gè)綁定加到 register
方法。然后你可以配置 Laravel 從 config/app.php
配置文件加載你的服務(wù)提供者。
接下來(lái),我們可以建立我們自己的 facade 類:
use Illuminate\Support\Facades\Facade;class Payment extends Facade { protected static function getFacadeAccessor() { return 'payment'; }}
最后,如果我們希望,可以在 config/app.php
配置文件為 facade 加個(gè)別名到 aliases
數(shù)組?,F(xiàn)在我們可以在 Payment
類的實(shí)例上調(diào)用 process
方法。
Payment::process();
在 aliases
數(shù)組中的類在某些實(shí)例中不能使用,因?yàn)?PHP 將不會(huì)嘗試去自動(dòng)加載未定義的類型提示類。如果 \ServiceWrapper\ApiTimeoutException
命別名為 ApiTimeoutException
,即便有異常被拋出,在 \ServiceWrapper
命名空間外面的 catch(ApiTimeoutException $e)
將永遠(yuǎn)捕捉不到異常。類似的問(wèn)題在有類型提示的別名類一樣會(huì)發(fā)生。唯一的替代方案就是放棄別名并用 use
在每一個(gè)文件的最上面引入你希望類型提示的類。
單元測(cè)試是為什么現(xiàn)在 facades 采用這樣的工作方式的主要因素。事實(shí)上,可測(cè)試性甚至是 facades 存在的主要理由。想要獲得更多信息,請(qǐng)查看文檔的 模擬 facades 章節(jié)。
你將會(huì)在下面找到每一個(gè) facade 和它的基礎(chǔ)類。這是個(gè)可以從一個(gè)給定的 facade 根源快速地深入 API 文檔的有用工具??蓱?yīng)用的 服務(wù)容器綁定 關(guān)鍵字也包含在里面。
更多建議: