Skip to main content

Facade 是什麼

Facade 為應用程式服務容器中可用的類別提供了「靜態」介面。Laravel 內建有大量 Facade,幾乎能存取所有功能。 Laravel 的 Facade 作為服務容器中實體類別的「靜態代理」運作,比起傳統的靜態方法更容易測試也更具彈性,同時提供簡潔且富有表達力的語法。 所有 Laravel Facade 都定義在 Illuminate\Support\Facades 命名空間下。
就算你還沒完全理解 Facade 的機制也沒關係。先熟悉用法,繼續學習 Laravel 即可。

Facade 的運作機制

在 Laravel 中,Facade 是提供對容器中物件存取權的類別。此機制由 Facade 基底類別實作。Laravel 的所有 Facade(含自訂 Facade)都繼承基底類別 Illuminate\Support\Facades\Facade Facade 基底類別使用 __callStatic() 魔術方法,將對 Facade 的呼叫委派給容器中解析出的物件。
檔案開頭引入了 Cache Facade。此 Facade 代理 Illuminate\Contracts\Cache\Factory 介面實作的存取。所有透過 Facade 的呼叫最終都會傳給 Laravel 快取服務的內部實例。 Illuminate\Support\Facades\Cache 類別會發現,並不存在靜態 get 方法。
Cache Facade 繼承 Facade 並定義了 getFacadeAccessor()。此方法回傳的是服務容器的繫結名稱。當使用者呼叫 Cache Facade 的靜態方法時,Laravel 會由容器解析出 cache 繫結,然後對該物件呼叫實際的方法(此例中的 get)。

何時該用、何時不該用 Facade

Facade 的優點

Facade 有許多優點。它讓你不必記憶必須手動注入設定的長類別名稱,就能以簡潔而好記的語法使用 Laravel 的功能。此外,因為 PHP 動態方法的獨特用法,Facade 也非常容易測試。

注意作用域擴散

使用 Facade 時最主要的風險是類別的「作用域擴散」。因為 Facade 好用且不需注入,容易讓類別越來越肥大,塞入大量 Facade。若使用依賴注入,龐大的建構子會提供視覺上的警告訊號。使用 Facade 時,請務必留意類別的大小、保持職責範圍夠小。
當覺得類別開始變得太大時,考慮拆成多個小類別。

Facade vs. 依賴注入

依賴注入的一大優點是可以替換所注入類別的實作,這在測試時很有用,可以注入 mock 或 stub,並斷言各方法是否被呼叫。 真正靜態的類別方法通常無法 mock 或 stub,但 Facade 是透過動態方法,代理呼叫到容器解析出的物件,因此可像對待被注入的類別實例一樣測試 Facade。
對這個路由可以撰寫以下測試,驗證 Cache::get 是以預期引數被呼叫。

Facade vs. 輔助函式

除了 Facade,Laravel 還提供「輔助函式」可執行像是產生視圖、觸發事件、派發 job、送出 HTTP 回應等常見任務。許多輔助函式與對應 Facade 的功能相同。
Facade 與輔助函式在本質上並無差別。即使使用輔助函式,也可以像對應 Facade 一樣進行測試。

即時 Facade

透過即時 Facade,可以將應用程式中的任意類別當作 Facade 使用。先看看沒有使用即時 Facade 的程式碼作為對照。 例如 Podcast 模型有一個 publish 方法,但發佈 podcast 需要注入 Publisher 實例。
使用即時 Facade 後,可保持同樣的可測試性,同時不必顯式傳入 Publisher 實例。要建立即時 Facade,只需在引入類別的命名空間前加上 Facades 前綴。
在使用即時 Facade 時,會用 Facades 前綴之後的介面或類別名稱,從服務容器中解析出 publisher 的實作。
即時 Facade 適合用在既想簡化測試 mock、又想擺脫將依賴當作引數傳遞的情境。

Facade 的測試

要測試 Facade 可用 shouldReceive 方法,會回傳 Mockery 的 mock 實例。Facade 實際上由服務容器解析與管理,因此比一般靜態類別容易測試許多。
常用的 mock 方法如下:

主要 Facade 一覽

以下為常用 Facade 及其對應實體類別、服務容器繫結名稱的對照表。

下一步

Contracts(契約)

學習與 Facade 相對應的 Contracts 概念及兩者的抉擇。
最後修改於 2026年8月2日