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 端點的應用程式中,MailServiceProviderBroadcastServiceProvider 也可能在請求過程中一次都不被載入。

是否應延遲化的判斷基準

  • 並非在所有請求中使用的服務(郵件、報表、外部 API Client 等)
  • 初始化時需要外部連線或讀取檔案的服務
  • 具有龐大物件圖的服務
  • 提供僅於 CLI 使用之指令的提供者
  • 註冊路由的提供者(如 loadRoutesFrom 等)
  • 註冊常時運作的中介層或例外處理器的提供者
  • 註冊 Eloquent Global Scope 或 Observer 的提供者
  • 於大多數請求都會被使用的輕量服務(延遲的額外負擔反而更大時)

相關頁面

套件開發基礎

解說以服務提供者為核心的 Laravel 套件開發方式。

套件的版本相容性管理

解說對應 Laravel 與 PHP 主版本更新的套件維護策略。
最後修改於 2026年8月2日