Skip to main content
Laravel 啟動時註冊的服務提供者,即便在請求過程中一次都沒使用其功能,仍會每次被載入。延遲服務提供者(Deferred Service Provider)能解決此問題,將載入延後至服務實際被使用為止。
本頁以套件開發基礎的知識為前提。建議先理解服務提供者的基本機制後再閱讀。

為什麼需要延遲提供者

一般的服務提供者於每次請求都會呼叫 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 檔。此檔案中儲存了延遲提供者所提供的服務清單。
透過此 manifest,Laravel 無需讀取檔案便能掌握「此服務由哪個提供者提供」。實際的提供者僅會在對應服務首次被解析時才會載入。
若新增或變更提供者,請重新產生 manifest。

內部運作流程


provides() 方法的重要性

若 provides() 中有遺漏,該服務將永遠無法被解析。
使用 $bindings / $singletons 屬性時,也同樣要納入 provides()。

延遲提供者的限制

延遲提供者適合於僅以向 Container 註冊綁定為目的的提供者。以下這類在 boot() 中進行的作業,其提供者無法延遲化。
可以在延遲提供者中撰寫 boot() 方法,但其內容在服務被解析前不會執行。若將「總是需要的處理」如路由或中介層寫在 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 主版本更新的套件維護策略。
最後修改於 2026年8月2日