Laravel 服務容器中物件綁定方法比較
方法 | bind() |
singleton() |
scoped() |
instance() |
---|---|---|---|---|
描述 | 每次解析時創建一個新的實例。 | 只創建一個實例,並在後續請求中返回同一實例。 | 在每個請求/作業生命周期內只創建一個實例,請求結束後會被清除。 | 將已存在的實例綁定到容器,每次解析時返回該實例。 |
優點 | - 每次請求都是全新實例,無狀態共享問題 - 記憶體使用乾淨 - 適合處理需要獨立狀態的邏輯 - 可為每個請求提供獨特配置 |
- 節省系統資源,只需創建一次實例 - 確保狀態一致性 - 適合共享配置和資源 - 高併發情況下性能較好 |
- 平衡了記憶體使用和狀態共享 - 請求內狀態共享但請求間隔離 - 適合Web請求場景 |
- 完全控制實例建立時機 - 可預先配置實例狀態 - 適合需要特定配置的服務 |
缺點 | - 需較多系統資源重複創建實例 - 高併發下可能影響性能 - 不適合需要共享狀態的場景 - 可能導致性能問題,因為每次都要創建新實例。 |
- 共享狀態可能導致難追蹤的bug - 不適合需要獨立狀態的場景 - 記憶體佔用持續到程式結束 - 測試需特別注意狀態重置 - 如果該實例持有狀態,可能會導致意外行為。 |
- 可能在長時間執行的任務中出現問題 - 需要理解請求生命週期 - 不適合CLI命令 |
- 較不靈活 - 無法動態調整實例配置 - 可能佔用啟動時的記憶體 - 不適合需要延遲加載或多個實例的情況。 |
使用情境 | 用於短期使用的服務或需要獨立狀態的類別。 | 用於全局共享服務,如日誌記錄器或配置管理器。 | 用於需要在請求中保持狀態但不希望跨請求的服務,如資料庫連接。 | 當你已經有一個實例並希望重複使用時,如共享配置對象。 |
範例 | 當你有一個 Product 類別,每次請求不同產品資料時,你希望每次都建立新的 Product 實例。 |
當你有一個 Logger 類別,你希望所有日誌寫入操作都使用同一個實例來保持一致性。 |
當你有一個 ShoppingCart 類別,在同一個請求中需要共享購物車狀態。 |
當你有一個 DatabaseConfig 類別,需要在應用啟動時就設定好連接參數。 |
範例
使用 bind()
$this->app->bind('Product', function () {
return new Product();
});
每次調用 app('Product')
都會返回一個新的 Product
實例。
使用 singleton()
$this->app->singleton('Logger', function () {
return new Logger();
});
每次調用 app('Logger')
都會返回相同的 Logger
實例。
使用 scoped()
$this->app->scoped(Transistor::class, function (Application $app) {
return new Transistor($app->make(PodcastParser::class));
});
在同一個請求生命週期內共享同一個實例,不同請求會建立新實例。
使用 instance()
$service = new Transistor(new PodcastParser);
$this->app->instance(Transistor::class, $service);
直接綁定一個已存在的實例到容器。
總結
Laravel 目前可以應用在很多不同類型的情境,像是 Web 請求、CLI 命令、Queue 工作、Console 指令等等。
所以,在選擇使用哪種綁定方法時,需要考慮到該服務在不同情境下的需求,以及是否需要共享狀態或配置。