本頁以套件開發基礎的知識為前提。建議先理解服務提供者的基本機制後再閱讀。
為什麼需要延遲提供者
一般的服務提供者於每次請求都會呼叫register() 與 boot()。像郵件、Queue、Cache 等並非每個頁面都使用的功能也都要每次初始化實屬浪費。
DeferrableProvider 介面
Illuminate\Contracts\Support\DeferrableProvider 是僅具備 provides() 方法的簡單介面。
基本實作
延遲提供者的實作分為 3 個步驟。1
implements DeferrableProvider
2
於 register() 綁定服務
與一般提供者相同,於
register() 撰寫綁定。3
於 provides() 回傳所註冊的服務
provides() 必須回傳於 register() 綁定的所有服務。Laravel 會依此清單判斷「當要求哪些服務時要載入此提供者」。Service Manifest 的機制
Laravel 於啟動時會產生一個bootstrap/cache/services.php 的 manifest 檔。此檔案中儲存了延遲提供者所提供的服務清單。
內部運作流程
provides() 方法的重要性
若provides() 中有遺漏,該服務將永遠無法被解析。
$bindings / $singletons 屬性時,也同樣要納入 provides()。
延遲提供者的限制
延遲提供者適合於僅以向 Container 註冊綁定為目的的提供者。以下這類在boot() 中進行的作業,其提供者無法延遲化。
when() 方法 — 由事件觸發的註冊
使用when() 方法,可在特定事件觸發時載入提供者。適用於 Job 處理系統等僅在特定情境下需要的提供者。
when() 中回傳的事件觸發時,即便服務未直接被解析,提供者也會被載入。
套件開發的活用
當作為第三方套件發布時,延遲提供者對使用者應用程式的效能也有幫助。建議的模式
mergeConfigFrom() 內部會檢查設定是否已快取,因此於延遲提供者的 register() 中呼叫也是安全的。但若設定已被快取則不會執行任何事。以 runningInConsole() 分離 Artisan 指令註冊
因為指令註冊僅在 Artisan 啟動時需要,可以透過 runningInConsole() 進行條件判斷。但若要延遲提供指令的提供者,需將指令類別也納入 provides(),或另外準備專用於指令的提供者。
Laravel Core 中的使用範例
Laravel Core 提供者中許多都是延遲提供者。這是為了不將每次請求不會用到的所有服務都立即載入的設計。
於僅有 API 端點的應用程式中,
MailServiceProvider 或 BroadcastServiceProvider 也可能在請求過程中一次都不被載入。
是否應延遲化的判斷基準
適合延遲化的服務
適合延遲化的服務
- 並非在所有請求中使用的服務(郵件、報表、外部 API Client 等)
- 初始化時需要外部連線或讀取檔案的服務
- 具有龐大物件圖的服務
- 提供僅於 CLI 使用之指令的提供者
不適合延遲化的服務
不適合延遲化的服務
- 註冊路由的提供者(如
loadRoutesFrom等) - 註冊常時運作的中介層或例外處理器的提供者
- 註冊 Eloquent Global Scope 或 Observer 的提供者
- 於大多數請求都會被使用的輕量服務(延遲的額外負擔反而更大時)
相關頁面
套件開發基礎
解說以服務提供者為核心的 Laravel 套件開發方式。
套件的版本相容性管理
解說對應 Laravel 與 PHP 主版本更新的套件維護策略。