Skip to main content

什麼是 Service Container

Laravel 的 service container 是管理類別依賴並進行依賴注入的機制。所謂依賴注入,是指透過建構子(或有時透過 setter 方法)將類別所需的依賴「注入」到類別中。 看以下例子:
此例中,PodcastController 需要從 Apple Music 等資料來源取得 Podcast。因此我們注入能取得 Podcast 的服務。透過注入服務,測試時能輕易換成 AppleMusic 服務的 mock(假實作)。
深入理解 service container 對於建構大型 Laravel 應用不可或缺,也對貢獻 Laravel 核心有所幫助。

零設定解析

若類別只依賴其他具體類別(非介面),無需告訴 container 如何解析。例如在 routes/web.php 寫下:
此例在路由檔中定義類別僅為示範。實際應用中,service 類別應定義於 app/Services 目錄。
存取此路由時,Laravel 會自動解析 Service 類別並注入到路由 handler。無需設定檔即可享受依賴注入。 controller、event listener、middleware 等 Laravel 應用中撰寫的多數類別,其依賴都會透過 container 自動注入。

Binding

基本 binding

多數 binding 會在service provider中登記。在 service provider 內可透過 $this->app 屬性存取 container。

bind

bind 方法傳入類別或介面名稱與 closure 來登記 binding。
Closure 的引數會收到 container 本身。可用它解析子依賴。 若要在 service provider 外操作 container,使用 App facade。
不依賴介面的類別不需要 bind 到 container。container 會以 reflection 自動解析這些物件。

singleton

singleton 方法會將類別或介面 bind 為只解析一次。一旦解析出的 singleton 之後每次向 container 呼叫都會回傳同一個實例。
使用 singletonIf 方法可以只在該型別尚未登記 binding 時才登記 singleton binding。

Singleton 屬性

也可以在類別或介面加上 #[Singleton] 屬性,指示 container 只解析一次。

Scoped singleton binding

scoped 方法將類別或介面 bind 為在 Laravel 請求/job 生命週期內只解析一次。與 singleton 類似,但以 scoped 登記的實例會在 Laravel 應用開始新的「生命週期」時被銷毀,例如 Laravel Octane worker 處理新請求,或 queue worker 處理新 job 時。
使用 scopedIf 方法可以只在該型別尚未登記 binding 時才登記 scoped binding。

Scoped 屬性

也可以在類別或介面加上 #[Scoped] 屬性,指示 container 在請求/job 生命週期內只解析一次。

instance

也可用 instance 方法將既有物件實例 bind 到 container。之後每次呼叫 container 都會回傳該實例。

將介面 bind 到實作

service container 強大功能之一是可以將介面 bind 到特定實作。例如有 EventPusher 介面與 RedisEventPusher 實作:
如此,container 會為需要 EventPusher 實作的類別注入 RedisEventPusher。之後只需在建構子 type-hint EventPusher 介面即可。
依賴介面就算換掉實作也不需改動程式碼。使測試與未來變更更容易。

Bind 屬性

Laravel 還提供更方便的 Bind 屬性。在介面加上此屬性,就可以告訴 Laravel 當該介面被要求時要自動注入哪個實作。使用 Bind 屬性時,service provider 中無需再登記。 還可以在介面放多個 Bind 屬性,依環境注入不同實作。
依任意條件的 binding,可用 BindWhen 屬性。closure 會收到 container,套用該 binding 時回傳 trueBindBindWhen 屬性會依宣告順序評估。
使用 BindWhen 屬性需要 PHP 8.5 以上。
也可與 SingletonScoped 屬性併用,指定該 container binding 是否只解析一次、或每個請求/job 只解析一次。

自動解析(以 type-hint 進行 DI)

service container 在解析 controller、event listener、middleware 等類別時,會查看建構子的 type-hint 自動注入依賴。
UserRepository 不依賴介面,就不用登記到 container。只要存取路由,container 就會自動解析依賴並注入到 controller。

從 Container 解析

make 方法

make 方法可從 container 解析類別實例。
若類別的依賴無法由 container 解析,也可用 makeWith 方法傳入額外引數。

自動注入

實際上,很少直接呼叫 make。只要在 container 會解析的類別(controller、event listener、middleware 等)建構子加上 type-hint,container 就會自動注入。

Facade 與 Container 的關係

Laravel 的 facade 為 container 內的物件提供靜態介面。例如 Cache::get() 內部會從 container 取得 Cache 服務再呼叫。
Facade 是 container 的便利包裝。測試時可將 facade 替換為 mock。

建構子注入的實務範例

看實際應用中的典型模式:
1

定義介面

2

建立實作類別

3

在 Service Provider bind

4

在 controller 接收注入

透過此模式,即使要把付款服務從 Stripe 換成其他供應商,也只需改一處 binding。

後續步驟

Service Provider

學習使用 service provider 登記 binding 的方式。
最後修改於 2026年8月2日