Documentation Index Fetch the complete documentation index at: https://kawax.biz/llms.txt
Use this file to discover all available pages before exploring further.
サービスコンテナとは
Laravelのサービスコンテナは、クラスの依存関係を管理し、依存性注入を行うための仕組みです。依存性注入とは、クラスが必要とする依存をコンストラクターや、場合によってはセッターメソッドを通じてクラスへ「注入」することを指します。
次の例を見てみましょう。
<? php
namespace App\Http\Controllers ;
use App\Services\ AppleMusic ;
use Illuminate\View\ View ;
class PodcastController extends Controller
{
/**
* 新しいコントローラーインスタンスを生成する
*/
public function __construct (
protected AppleMusic $apple ,
) {}
/**
* 指定されたポッドキャストの情報を表示する
*/
public function show ( string $id ) : View
{
return view ( 'podcasts.show' , [
'podcast' => $this -> apple -> findPodcast ( $id )
]);
}
}
この例では、PodcastController はApple MusicなどのデータソースからPodcastを取得する必要があります。そこで、Podcastを取得できるサービスを注入 します。サービスを注入することで、テスト時にAppleMusicサービスのモック(ダミー実装)を簡単に差し替えられます。
サービスコンテナを深く理解することは、大規模なLaravelアプリケーションを構築するうえで不可欠です。Laravelコア自体への貢献にも役立ちます。
ゼロコンフィギュレーション解決
クラスが他の具体クラス(インターフェースではない)にしか依存していない場合、コンテナにその解決方法を教える必要はありません。例えば、次のコードをroutes/web.phpに書いたとします。
<? php
class Service
{
// ...
}
Route :: get ( '/' , function ( Service $service ) {
dd ( $service :: class );
});
この例はルートファイル内でクラスを定義していますが、これはデモ用です。実際のアプリケーションでは、サービスクラスは app/Services ディレクトリに定義してください。
このルートにアクセスすると、Laravelは自動的にServiceクラスを解決してルートハンドラーへ注入します。設定ファイルを用意しなくても依存性注入の恩恵を受けられます。
コントローラー、イベントリスナー、ミドルウェアなど、Laravelアプリケーションで書くクラスの多くは、コンテナを通じて自動的に依存が注入されます。
バインディング
基本的なバインディング
ほとんどのバインディングはサービスプロバイダ 内で登録します。サービスプロバイダ内では $this->app プロパティを通じてコンテナにアクセスできます。
bind
bind メソッドを使って、クラスまたはインターフェース名とクロージャを渡してバインディングを登録します。
use App\Services\ Transistor ;
use App\Services\ PodcastParser ;
use Illuminate\Contracts\Foundation\ Application ;
$this -> app -> bind ( Transistor :: class , function ( Application $app ) {
return new Transistor ( $app -> make ( PodcastParser :: class ));
});
クロージャの引数としてコンテナ自身を受け取ることができます。これを使ってサブ依存を解決できます。
サービスプロバイダの外でコンテナを操作したい場合は App ファサードを使います。
use App\Services\ Transistor ;
use Illuminate\Contracts\Foundation\ Application ;
use Illuminate\Support\Facades\ App ;
App :: bind ( Transistor :: class , function ( Application $app ) {
// ...
});
インターフェースに依存しないクラスはコンテナへバインドする必要はありません。コンテナはリフレクションを使ってこれらのオブジェクトを自動的に解決できます。
singleton
singleton メソッドは、クラスまたはインターフェースを一度だけ解決するようにバインドします。一度解決されたシングルトンは、以降のコンテナへの呼び出しで同じインスタンスが返されます。
use App\Services\ Transistor ;
use App\Services\ PodcastParser ;
use Illuminate\Contracts\Foundation\ Application ;
$this -> app -> singleton ( Transistor :: class , function ( Application $app ) {
return new Transistor ( $app -> make ( PodcastParser :: class ));
});
instance
既存のオブジェクトインスタンスを instance メソッドでコンテナにバインドすることもできます。以降のコンテナへの呼び出しでは常にそのインスタンスが返されます。
use App\Services\ Transistor ;
use App\Services\ PodcastParser ;
$service = new Transistor ( new PodcastParser );
$this -> app -> instance ( Transistor :: class , $service );
インターフェースを実装にバインドする
サービスコンテナの強力な機能の一つは、インターフェースを特定の実装にバインドできることです。例えば、EventPusher インターフェースと RedisEventPusher 実装があるとします。
use App\Contracts\ EventPusher ;
use App\Services\ RedisEventPusher ;
$this -> app -> bind ( EventPusher :: class , RedisEventPusher :: class );
これにより、コンテナは EventPusher の実装が必要なクラスに RedisEventPusher を注入するようになります。あとはコンストラクターで EventPusher インターフェースをタイプヒントするだけです。
use App\Contracts\ EventPusher ;
/**
* 新しいクラスインスタンスを生成する
*/
public function __construct (
protected EventPusher $pusher ,
) {}
インターフェースに依存することで、実装を差し替えてもコードを変更する必要がなくなります。これにより、テストや将来の変更が容易になります。
自動解決(型ヒントによるDI)
サービスコンテナは、コントローラー、イベントリスナー、ミドルウェアなどのクラスを解決する際に、コンストラクターの型ヒントを見て依存を自動的に注入します。
<? php
namespace App\Http\Controllers ;
use App\Repositories\ UserRepository ;
class UserController extends Controller
{
/**
* 新しいコントローラーインスタンスを生成する
*/
public function __construct (
protected UserRepository $users ,
) {}
}
UserRepository がインターフェースに依存していなければ、コンテナへの登録は不要です。次のルートにアクセスするだけで、コンテナが自動的に依存を解決してコントローラーに注入します。
コンテナからの解決
makeメソッド
make メソッドを使って、コンテナからクラスインスタンスを解決できます。
use App\Services\ Transistor ;
$transistor = app () -> make ( Transistor :: class );
クラスの依存がコンテナで解決できない場合、makeWith メソッドを使って追加の引数を渡すこともできます。
$transistor = $this -> app -> makeWith ( Transistor :: class , [ 'id' => 1 ]);
自動注入
実際には、make メソッドを直接呼び出すことはほとんどありません。コンテナが解決するクラス(コントローラー、イベントリスナー、ミドルウェアなど)のコンストラクターに型ヒントを追加するだけで、コンテナが自動的に注入してくれます。
ファサードとコンテナの関係
Laravelのファサードは、コンテナ内のオブジェクトへの静的インターフェースを提供します。例えば、Cache::get() は内部的にコンテナから Cache サービスを取得して呼び出しています。
use Illuminate\Support\Facades\ Cache ;
// ファサードを使った呼び出し
Cache :: get ( 'key' );
// コンテナを直接使った同等の呼び出し
app ( 'cache' ) -> get ( 'key' );
ファサードはコンテナの便利なラッパーです。テスト時にはファサードをモックに差し替えることもできます。
use Illuminate\Support\Facades\ Cache ;
Cache :: shouldReceive ( 'get' )
-> once ()
-> with ( 'key' )
-> andReturn ( 'value' );
コンストラクターインジェクションの実践例
実際のアプリケーションでの典型的なパターンを見てみましょう。
インターフェースを定義する
<? php
namespace App\Contracts ;
interface PaymentGateway
{
public function charge ( int $amount , string $token ) : bool ;
}
実装クラスを作成する
<? php
namespace App\Services ;
use App\Contracts\ PaymentGateway ;
class StripePaymentGateway implements PaymentGateway
{
public function charge ( int $amount , string $token ) : bool
{
// Stripe APIを使った決済処理...
return true ;
}
}
サービスプロバイダでバインドする
use App\Contracts\ PaymentGateway ;
use App\Services\ StripePaymentGateway ;
$this -> app -> singleton ( PaymentGateway :: class , StripePaymentGateway :: class );
コントローラーで注入を受け取る
<? php
namespace App\Http\Controllers ;
use App\Contracts\ PaymentGateway ;
use Illuminate\Http\ Request ;
class OrderController extends Controller
{
public function __construct (
protected PaymentGateway $payment ,
) {}
public function store ( Request $request )
{
$this -> payment -> charge (
$request -> amount ,
$request -> payment_token
);
// ...
}
}
このパターンにより、決済サービスをStripeから別のプロバイダに切り替える場合も、バインディングを1か所変更するだけで対応できます。
次のステップ
サービスプロバイダ サービスプロバイダを使ってバインディングを登録する方法を学びます。