Laravel サービス コンテナは、クラスの依存関係を管理し、依存関係の注入を実行するための強力なツールです。依存関係の注入というと派手に聞こえますが、その本質は、コンストラクターまたは場合によっては set メソッドを通じてクラスの依存関係をクラスに注入することです。
簡単な例を見てみましょう:
<?phpnamespace App\Jobs;use App\User;use Illuminate\Contracts\Mail\Mailer;use Illuminate\Contracts\Bus\SelfHandling;class PurchasePodcast implements SelfHandling{ /** * 邮件实现 */ protected $mailer; /** * 创建一个新的实例 * * @param Mailer $mailer * @return void */ public function __construct(Mailer $mailer) { $this->mailer = $mailer; } /** * 购买一个播客 * * @return void */ public function handle() { // }}
この場合、PurchasePodcast タスクはポッドキャストの購入時に電子メールを送信する必要があるため、送信できるサービスを挿入する必要があります。電子メール。サービスは挿入されるため、そのサービスを別の実装に簡単に置き換えることができ、テスト中に偽の電子メール実装を「シミュレート」したり作成したりすることもできます。
Laravel サービスコンテナを深く理解することは、大規模で強力な Laravel アプリケーションを構築するために不可欠であり、Laravel コアにコードを貢献するのにも役立ちます。
ほとんどすべてのサービス コンテナーのバインドはサービス プロバイダーで行われます。したがって、この章のデモ例で使用されるコンテナーはすべてこのコンテキスト内にあります。クラスがインターフェイスに基づいていない場合は、それをコンテナーにバインドする必要はありません。コンテナは PHP のリフレクション サービスを使用して特定のオブジェクトを自動的に解決するため、オブジェクトの構築方法をコンテナに指示する必要はありません。
サービス プロバイダーでは、$this->app 変数を通じてコンテナにアクセスし、bind メソッドを使用してバインディングを登録できます。このメソッドには 2 つのパラメーターが必要です。登録するクラス名またはインターフェイス名。2 番目のパラメータはクラスのインスタンスを返すクロージャです:
$this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app['HttpClient']);});
コンテナ自体をパーサーへの引数として受け入れることができることに注意してください。次に、構築中のオブジェクトのサブ依存関係を解析するために使用します。
シングルトン メソッドは、一度解決するだけで済むクラスまたはインターフェイスをコンテナにバインドします。その後、コンテナに対する後続の呼び出しでは同じインスタンスが返されます。
$this->app->singleton('FooBar', function ($app) { return new FooBar($app['SomethingElse']);});
インスタンス メソッドを使用して、既存のオブジェクト インスタンスをコンテナにバインドすることもできます。コンテナに対する後続の呼び出しでは、常に指定されたインスタンスが返されます:
$fooBar = new FooBar(new SomethingElse);$this->app->instance('FooBar', $fooBar);
サービス コンテナの非常に強力な機能は、インターフェイスを実装にバインドできることです。 EventPusher インターフェイスとその RedisEventPusher 実装があることを前提としています。インターフェイスの RedisEventPusher 実装を作成した後、それをサービス コンテナーに登録できます。
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
このコードは、クラスがいつリクエストを必要とするかをコンテナーに伝えます。 EventPusher の実装 RedisEventPusher が挿入されるようになりました。これで、コンストラクターまたはサービス コンテナーを通じて依存関係が挿入されるその他の場所で、EventPusher インターフェイスにヒントを入力できるようになります。同じインターフェイスを使用する 2 つのクラスが存在する可能性がありますが、各クラスに異なる実装を挿入したいとします。たとえば、システムが新しい注文を受け取ったときに、Pusher ではなく PubNub 経由でイベントを送信したいと考えています。 Laravel は、この動作を定義するためのシンプルでスムーズな方法を定義しています:
use App\Contracts\EventPusher;/** * 创建一个新的类实例 * * @param EventPusher $pusher * @return void */public function __construct(EventPusher $pusher){ $this->pusher = $pusher;}
$this->app->when('App\Handlers\Commands\CreateOrderHandler') ->needs('App\Contracts\EventPusher') ->give('App\Services\PubNubEventPusher');
$this->app->when('App\Handlers\Commands\CreateOrderHandler') ->needs('App\Contracts\EventPusher') ->give(function () { // Resolve dependency... });
タグ
場合によっては、レポート アグリゲーターを登録した後、複数の異なるレポート インターフェイスの実装を受け取るアプリケーションを構築しているとします。 Report 実装では、タグ メソッドを使用してサービスにタグを割り当てることができます:
$this->app->when('App\Handlers\Commands\CreateOrderHandler') ->needs('$maxOrderCount') ->give(10);
3. 解析
$this->app->bind('SpeedReport', function () { //});$this->app->bind('MemoryReport', function () { //});$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
コンテナからオブジェクトを解析するには、さまざまな方法があります。まず、解析するクラス名またはインターフェイス名を受け取る make メソッドを使用します。 :
$this->app->bind('ReportAggregator', function ($app) { return new ReportAggregator($app->tagged('reports'));});
最後に、最も一般的に使用されるのは、単にオブジェクトを解決することです。この方法で、クラスのコンストラクター内の依存関係 (コントローラー、イベント リスナー、キュー タスク、ミドルウェアなど) をタイプヒントでコンテナーに追加できます。実際には、これがほとんどのオブジェクトがコンテナから解決される方法です。
$fooBar = $this->app->make('FooBar');
$fooBar = $this->app['FooBar'];
サービス コンテナは、オブジェクトを解析するたびにイベントをトリガーします。解決メソッドを使用してイベントをリッスンできます。
<?phpnamespace App\Http\Controllers;use Illuminate\Routing\Controller;use App\Users\Repository as UserRepository;class UserController extends Controller{ /** * 用户仓库实例 */ protected $users; /** * 创建一个控制器实例 * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 通过指定ID显示用户 * * @param int $id * @return Response */ public function show($id) { // }}