Laravel 服務容器(Service
Container)
Laravel 服務容器是一個強大的工具,用來管理類別依賴與實現依賴注入(Dependency Injection, DI)。簡單來說,就是將其他物件的依賴「注入」進來,而不是在類別內部自行
new。
依賴注入(Dependency Injection,
DI)
介紹
依賴注入是一種設計模式,讓類別依賴「抽象」而非具體的實作,能夠減少耦合、提升測試性與重用性。
被依賴的物件通常會透過建構子、方法參數或屬性被注入,而不是在類別內部直接建立。
使用時機
- 使用介面導向程式設計時(如透過介面實作多型)
- 建構子參數中需要其他服務(尤其是非 Laravel 可自動解析的)
- 開發 Laravel 套件,並希望讓使用者可自定義替代服務實作
自動解析(Auto-Resolving)
Laravel 可以自動解析的情況
Laravel 能自動解析類別(無需手動綁定)條件如下:
- 所有依賴都是具體類別(非介面、非 primitive)
- 無建構子額外參數(如陣列、字串、整數等)
- 無需單例
即使多層依賴(A 依賴 B,B 依賴 C),Laravel 仍會自動解析:
必須手動綁定的情況
1. 建構子包含
Laravel 無法解析的類型(如 array、string)
2. 依賴介面(Interface)
3. 單例需求(Singleton)
綁定類型
bind(每次呼叫產生新的實例)
bind to closure(自定義建立邏輯)
singleton(全域只產生一次)
instance(立即指定一個現有實例)
Contextual
Binding(基於上下文的綁定)
當有多個介面實作,並希望根據不同情境注入不同的實作時使用:
契約(Contracts)
契約介紹
Laravel 的 Contracts 是一組定義框架核心功能的介面。目的是讓開發者依賴「抽象」而不是具體實作,達到更高的可替換性、可測試性、與解耦。
Contract 範例
定義 Contract
實作 Contract
綁定 Contract 到實作
在 Controller 中使用 Contract
單例模式(Singleton Pattern)
在某些情況下,不希望某個類別重複建立實例,可使用 Singleton Pattern。
PHP Singleton 實作
app()->make() 建立實例
除了依賴注入外,也可以用 app()->make() 顯式建立服務:
小結
| 類型 |
說明 |
| bind |
每次呼叫產生新實例 |
| singleton |
全域單一實例,共用 |
| instance |
已建立好的實例注入 |
| interface bind |
將介面綁定至實作 |
| contextual |
特定類別使用特定實作 |
| auto-resolve |
沒有 interface/primitive 時 Laravel 可自動解析 |
Laravel 服務容器(Service Container)
依賴注入(Dependency Injection, DI)
介紹
使用時機
自動解析(Auto-Resolving)
Laravel 可以自動解析的情況
Laravel 能自動解析類別(無需手動綁定)條件如下:
class ConfigService { public function getConfig() { return "載入設定..."; } } class SimpleService { public function __construct(ConfigService $config) { $this->config = $config; } public function doSomething() { return $this->config->getConfig(); } } class SimpleController extends Controller { public function __construct(SimpleService $service) { $this->service = $service; } public function index() { return $this->service->doSomething(); } }即使多層依賴(A 依賴 B,B 依賴 C),Laravel 仍會自動解析:
必須手動綁定的情況
1. 建構子包含 Laravel 無法解析的類型(如 array、string)
class SimpleService { public function __construct(array $config) { $this->config = $config; } } $this->app->bind(SimpleService::class, function ($app) { return new SimpleService(['debug' => true]); });2. 依賴介面(Interface)
interface ConfigServiceInterface { public function getConfig(); } class ConfigService implements ConfigServiceInterface { public function getConfig() { return "載入設定..."; } } class SimpleService { public function __construct(ConfigServiceInterface $config) { $this->config = $config; } } $this->app->bind(ConfigServiceInterface::class, ConfigService::class);3. 單例需求(Singleton)
$this->app->singleton(SimpleService::class, function ($app) { return new SimpleService($app->make(ConfigService::class)); });綁定類型
bind(每次呼叫產生新的實例)
$this->app->bind(PaymentGateway::class, StripePaymentGateway::class);bind to closure(自定義建立邏輯)
$this->app->bind(PaymentGateway::class, function ($app) { return new StripePaymentGateway(); });singleton(全域只產生一次)
$this->app->singleton(PaymentGateway::class, function ($app) { return new StripePaymentGateway(); });instance(立即指定一個現有實例)
$gateway = new StripePaymentGateway(); $this->app->instance(PaymentGateway::class, $gateway);Contextual Binding(基於上下文的綁定)
當有多個介面實作,並希望根據不同情境注入不同的實作時使用:
$this->app->when(StripePaymentController::class) ->needs(PaymentGateway::class) ->give(StripePaymentGateway::class); $this->app->when(PayPalPaymentController::class) ->needs(PaymentGateway::class) ->give(PayPalPaymentGateway::class);契約(Contracts)
契約介紹
Contract 範例
定義 Contract
// app/Contracts/PaymentGateway.php namespace App\Contracts; interface PaymentGateway { public function charge($amount); }實作 Contract
// app/Services/StripePaymentGateway.php namespace App\Services; use App\Contracts\PaymentGateway; class StripePaymentGateway implements PaymentGateway { public function charge($amount) { return "Charged {$amount} using Stripe"; } }綁定 Contract 到實作
$this->app->bind(PaymentGateway::class, StripePaymentGateway::class);在 Controller 中使用 Contract
use App\Contracts\PaymentGateway; class PaymentController extends Controller { public function __construct(PaymentGateway $paymentGateway) { $this->paymentGateway = $paymentGateway; } public function charge() { return $this->paymentGateway->charge(100); } }單例模式(Singleton Pattern)
在某些情況下,不希望某個類別重複建立實例,可使用 Singleton Pattern。
PHP Singleton 實作
class Singleton { private static $instance; private function __construct() {} private function __clone() {} private function __wakeup() {} public static function getInstance() { if (!self::$instance) { self::$instance = new self(); } return self::$instance; } } $singleton = Singleton::getInstance();app()->make() 建立實例
除了依賴注入外,也可以用
app()->make()顯式建立服務:public function store() { $request = app()->make(Request::class); $data = $request->all(); // ... }小結