Featured image of post 在 Laravel 的 bind()、singleton()、scoped()、instance() 的邏輯差異是什麼?可以在什麼樣的情境下使用?

在 Laravel 的 bind()、singleton()、scoped()、instance() 的邏輯差異是什麼?可以在什麼樣的情境下使用?

在 Laravel 的 bind()、singleton()、scoped()、instance() 的邏輯差異是什麼?可以在什麼樣的情境下使用?

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 指令等等。

所以,在選擇使用哪種綁定方法時,需要考慮到該服務在不同情境下的需求,以及是否需要共享狀態或配置。

Reference

All rights reserved,未經允許不得隨意轉載
Built with Hugo
Theme Stack designed by Jimmy