サービスコンテナ
- 基本バインディング
- 単純なバインディング
- シングルトンのバインド
- インスタンスのバインド
- 基本値のバインド
- #インターフェイスを実装にバインド
- #コンテキスト バインディング #マーキング
- 拡張バインディング
- インスタンスの解析
- make メソッド #自動インジェクション
- PSR-11
<?php namespace App\Http\Controllers; use App\User; use App\Repositories\UserRepository; use App\Http\Controllers\Controller; class UserController extends Controller{ /** * 用户存储库的实现. * * @var UserRepository */ protected $users; /** * 创建新的控制器实例. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 显示指定用户的 profile. * * @param int $id * @return Response */ public function show($id) { $user = $this->users->find($id); return view('user.profile', ['user' => $user]); } }この例では、コントローラー
UserController がデータ ソースからユーザーを取得する必要があります。したがって、ユーザーを獲得できるサービスを
inject する必要があります。現在のコンテキストでは、UserRepository は Eloquent を使用してデータベースからユーザー情報を取得している可能性が高くなります。ただし、リポジトリは注入されるため、別の実装に簡単に切り替えることができます。この注入方法の利便性は、アプリケーションのテストを作成するときに、
UserRepository の仮想実装を簡単に「モック」または作成できることにも反映されています。
{ヒント} コンテナーがどのインターフェースにも依存していない場合、このコンテナー内のクラスをバインドする必要はありません。コンテナはリフレクションを使用してこれらのオブジェクトを自動的に解決できるため、これらのオブジェクトの構築方法を指定する必要はありません。
サービス プロバイダーでは、単純なバインディング
$this->app
プロパティを通じていつでもコンテナーにアクセスできます。コンテナのbind メソッドを使用してバインディングを登録できます。
bind メソッドの最初のパラメータはバインドされるクラス/インターフェイス名で、2 番目のパラメータは戻りクラスのインスタンスです。 .
Closure:
$this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
コンテナ自体をパーサーへの引数として受け入れることに注意してください。その後、コンテナを使用して、構築中のオブジェクトのサブ依存関係を解決できます。
Bind a singletonsingleton
メソッドは、クラスまたはインターフェイスを 1 回だけ解決されるコンテナにバインドします。シングルトン バインディングが解決されると、後続の呼び出しで同じオブジェクト インスタンスがコンテナに返されます。$this->app->singleton('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
インスタンスのバインド
instance
メソッドを使用して、既存のオブジェクト インスタンスをコンテナにバインドすることもできます。指定されたインスタンスは、後続の呼び出しで常にコンテナーに返されます:
$api = new HelpSpot\API(new HttpClient); $this->app->instance('HelpSpot\API', $api);
基本値のバインディング
注入されたクラスを受け入れる必要があるだけでなく、注入する必要があるクラスがある場合基本的な値 (整数など)。コンテキスト バインディングを使用すると、クラスに必要な値を簡単に挿入できます。
$this->app->when('App\Http\Controllers\UserController') ->needs('$variableName') ->give($value);
インターフェイスを実装にバインドします
サービス コンテナには、非常に強力な機能は、インターフェイスを指定された実装にバインドするためのサポートです。たとえば、EventPusher
インターフェイスと RedisEventPusher
実装があるとします。 EventPusher
インターフェイスの RedisEventPusher
実装を作成したら、次のようにサービス コンテナに登録できます。
$this->app->bind( 'App\Contracts\EventPusher', 'App\Services\RedisEventPusher' );
そうすることは、コンテナ: when クラスが EventPusher
を実装する必要がある場合、RedisEventPusher
を注入する必要があります。これで、タイプ ヒントを使用して、コンストラクターまたはサービス コンテナーを通じて依存関係が挿入される他の場所に EventPusher
インターフェイスを挿入できるようになりました。 # Context Binding
同じインターフェイスを使用する 2 つのクラスがあり、それぞれに異なる実装を挿入したい場合があります。たとえば、2 つのコントローラーが Illuminate\Contracts\Filesystem\Filesystem コントラクトに依存する場合があります。Laravel は、この動作を定義するためのシンプルでエレガントなインターフェイスを提供します:
use App\Contracts\EventPusher; /** * Create a new class instance. * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher){ $this->pusher = $pusher; }
マーク
# 場合によっては、特定の「カテゴリ」の下にあるすべてのバインディングを解析する必要がある場合があります。たとえば、さまざまな Report インターフェイス実装の配列を受け取るレポート アグリゲーターを構築しているとします。
Report実装を登録した後、
tag メソッドを使用してタグを割り当てることができます。
サービスにタグが付けられたら、## 経由で割り当てることができます。 #taggeduse Illuminate\Support\Facades\Storage;
use App\Http\Controllers\PhotoController;
use App\Http\Controllers\VideoController;
use Illuminate\Contracts\Filesystem\Filesystem;
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});
$this->app->when([VideoController::class, UploadController::class])
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});
簡単に解析するメソッド:
$this->app->bind('SpeedReport', function () { // }); $this->app->bind('MemoryReport', function () { // }); $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
バインディングの拡張
extend メソッドは解決されたサービスを変更できます。たとえば、サービスが解決された後、追加のコードを追加してサービスを装飾または構成できます。 extend
このメソッドは、唯一のパラメータがサービスであるクロージャを受け入れ、変更されたサービスを返します:$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports'));
});
分析例
make
メソッド メソッドを使用して、コンテナ Example からクラスを解決できます。make メソッドは、解決するクラスまたはインターフェイスの名前を受け入れます:
$this->app->extend(Service::class, function ($service) {
return new DecoratedService($service);
});
コードが $app 変数にアクセスできない位置にある場合、グローバル ヘルパー関数
resolve を使用して解決できます。
$api = $this->app->make('HelpSpot\API');クラスの依存関係をコンテナーで解決できない場合は、クラスの依存関係を # の引数として連想配列として注入することで注入できます。 ##makeWith
メソッド:
$api = resolve('HelpSpot\API');
自動注入
さらに、さらに重要なことは、「型ヒント」を使用して、クラスのコンストラクター (コントローラーやイベントなど) のコンテナーによって解決する必要がある依存関係を簡単に注入できることです。 、キュータスク、ミドルウェアなど。実際、これはほとんどのオブジェクトがコンテナによって解決される方法です。
たとえば、コントローラーのコンストラクターにリポジトリ タイプのヒントを追加すると、リポジトリが自動的に解析されてクラスに挿入されます。
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);
コンテナ イベント
サービス コンテナがオブジェクトを解析するたびに、イベントがトリガーされます。resolve
メソッドを使用して、このイベントをリッスンできます:
<?php namespace App\Http\Controllers; use App\Users\Repository as UserRepository; class UserController extends Controller{ /** * The user repository instance. */ protected $users; /** * Create a new controller instance. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * Show the user with the given ID. * * @param int $id * @return Response */ public function show($id) { // } }
あなたが言ったように、ご覧のとおり、解析されたオブジェクトはコールバック関数に渡されるため、呼び出し元に渡される前にオブジェクトに追加のプロパティを設定できます。
PSR-11
Laravel のサービスコンテナは PSR-11 インターフェースを実装します。したがって、PSR-11 コンテナの「インターフェイス タイプ ヒント」を使用して、Laravel コンテナのインスタンスを取得できます。
$this->app->resolving(function ($object, $app) { // Called when container resolves object of any type... }); $this->app->resolving(HelpSpot\API::class, function ($api, $app) { // Called when container resolves objects of type "HelpSpot\API"... });
指定された識別子を解決できない場合は、例外がスローされます。識別子がバインドされていない場合、Psr\Container\NotFoundExceptionInterface
例外がスローされます。識別子がバインドされているが解決できない場合、Psr\Container\ContainerExceptionInterface
例外がスローされます。