Laravelサービスコンテナにおけるオブジェクトバインディング方法の比較
| 方法 | bind() |
singleton() |
scoped() |
instance() |
|---|---|---|---|---|
| 説明 | 解決されるたびに新しいインスタンスを作成します。 | インスタンスを1つだけ作成し、後続のリクエストでは同じインスタンスを返します。 | 各リクエスト/ジョブのライフサイクル内でインスタンスを1つだけ作成し、リクエスト終了後にクリアされます。 | 既存のインスタンスをコンテナにバインドし、解決されるたびにそのインスタンスを返します。 |
| メリット | - リクエストごとに新しいインスタンスが作成されるため、状態共有の問題がない - メモリ使用がクリーン - 独立した状態を必要とするロジックに適している - リクエストごとに独自の構成を提供できる |
- インスタンスを1回作成するだけで済むため、システムリソースを節約できる - 状態の一貫性を確保できる - 構成やリソースの共有に適している - 高同時実行性の場合にパフォーマンスが向上する |
- メモリ使用量と状態共有のバランスが取れている - リクエスト内では状態を共有し、リクエスト間では分離される - Webリクエストのシナリオに適している |
- インスタンス作成のタイミングを完全に制御できる - インスタンスの状態を事前に構成できる - 特定の構成を必要とするサービスに適している |
| デメリット | - インスタンスを繰り返し作成するために多くのシステムリソースが必要 - 高同時実行下ではパフォーマンスに影響を与える可能性がある - 状態共有が必要なシナリオには適さない - 毎回新しいインスタンスを作成するため、パフォーマンスの問題を引き起こす可能性がある。 |
- 状態の共有は、追跡が難しいバグにつながる可能性がある - 独立した状態が必要なシナリオには適さない - プログラム終了までメモリ使用が継続する - テストでは状態のリセットに特別な注意が必要 - そのインスタンスが状態を保持している場合、予期しない動作を引き起こす可能性がある。 |
- 長時間実行されるタスクで問題が発生する可能性がある - リクエストのライフサイクルを理解する必要がある - 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コマンドなど、さまざまなタイプのシナリオに適用できます。
そのため、どのバインディング方法を使用するかを選択する際には、さまざまなシナリオでのサービスのニーズ、および状態や構成を共有する必要があるかどうかを考慮する必要があります。