Laravel5.1学習ノート12システムアーキテクチャ4サービスコンテナ
16186 ワード
Service Container
#紹介
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected"into the class via the constructor or, in some cases, "setter"methods.
Let's look at a simple example:
Laravelサービスコンテナはクラス依存を管理する強力なツールであり、依存注入は比較的専門的な説であり、本当の意味はクラス依存をコンストラクタ、またはsetterメソッドを通じて注入することである.簡単な例を見てみましょう.
<?php
namespace App\Jobs;
use App\User;
use Illuminate\Contracts\Mail\Mailer;
use Illuminate\Contracts\Bus\SelfHandling;
class PurchasePodcast implements SelfHandling
{
/**
* The mailer implementation.
*/
protected $mailer;
/**
* Create a new instance.
*
* @param Mailer $mailer
* @return void
*/
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
/**
* Purchase a podcast.
*
* @return void
*/
public function handle()
{
//
}
}
In this example, the
PurchasePodcast
job needs to send e-mails when a podcast is purchased. So, we will inject a service that is able to send e-mails. Since the service is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the mailer when testing our application. この例では、ポッドキャストが購入されると、PurchasePodcastコマンドプロセッサは電子メールを送信する必要があります.だから、私たちはこの能力を提供するためにサービスを注入します.このサービスが注入されると,我々は簡単に異なる実装に切り替えることができる.アプリケーションをテストするときも、簡単に「シミュレーション」したり、仮想的な送信サービス実装を作成したりして、テストを支援することができます.
A deep understanding of the Laravel service container is essential to building a powerful, large application, as well as for contributing to the Laravel core itself.
強力で大規模なアプリケーションを作成したり、Laravelのカーネルに貢献したりするには、まずLaravelのサービスコンテナを深く理解する必要があります.
#バインド#バインド#
Almost all of your service container bindings will be registered within service providers , so all of these examples will demonstrate using the container in that context. However, there is no need to bind classes into the container if they do not depend on any interfaces. The container does not need to be instructed how to build these objects, since it can automatically resolve such "concrete"objects using PHP's reflection services.
Within a service provider, you always have access to the container via the
$this->app
instance variable. We can register a binding using the bind
method, passing the class or interface name that we wish to register along with a Closure
that returns an instance of the class: (ここ5.0のドキュメントの翻訳は正確ではなく、頭がまっすぐに見えます.私はこのように翻訳します:)ほとんどのサービスコンテナのバインドは、サービスプロバイダの中で発生しているので、これらの例はすべて上の文脈の下でコンテナを使用するときに示されています.しかし、インタフェースに依存しない場合は、コンテナにクラスをバインドする必要はありません.コンテナは、PHPの反射サービスを使用してこの「特定の」オブジェクトを自動的に解析するため、これらのオブジェクトの作成方法を通知する必要はありません.
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
Notice that we receive the container itself as an argument to the resolver. We can then use the container to resolve sub-dependencies of the object we are building.
私たちの解析器は1つのコンテナオブジェクトを引数として受信することに気づいて、私たちはそれからこのコンテナを使って下のバインドする必要があるオブジェクトを解析することができます.
単一のインスタンスをバインド
The
singleton
method binds a class or interface into the container that should only be resolved one time, and then that same instance will be returned on subsequent calls into the container: singletonメソッドはクラスまたはインタフェースをコンテナにバインドし、一度だけ解析され、その後の同じインスタンスは後で呼び出されてコンテナに返されます.
$this->app->singleton('FooBar', function ($app) {
return new FooBar($app['SomethingElse']);
});
既存のインスタンスをバインド
You may also bind an existing object instance into the container using the
instance
method. The given instance will always be returned on subsequent calls into the container: Instanceメソッドを使用して、既存のインスタンスをコンテナにバインドし、常にそのインスタンスを返すこともできます.
$fooBar = new FooBar(new SomethingElse);
$this->app->instance('FooBar', $fooBar);
#インスタンスをインタフェースにバインド
A very powerful feature of the service container is its ability to bind an interface to a given implementation. For example, let's assume we have an
EventPusher
interface and a RedisEventPusher
implementation. Once we have coded our RedisEventPusher
implementation of this interface, we can register it with the service container like so: サービスコンテナの強力な特性は、インタフェースに所与の実装をバインドできることです.例えば、EventPusherインタフェースとRedisEventPusher実装を仮定し、RedisEventPusher実装を実装すると、RedisEventPusherを実装すると、サービスコンテナでバインドできます.
$this->app->bind('App\Contracts\EventPusher', 'App\Services\RedisEventPusher');
This tells the container that it should inject the
RedisEventPusher
when a class needs an implementation of EventPusher
. Now we can type-hint the EventPusher
interface in a constructor, or any other location where dependencies are injected by the service container: これは、クラスがEventPusherの実装を必要とする場合、RedisEventPusherを注入する必要があることを示しています.これにより、クラスのコンストラクタでタイプヒント(type-hint)EventPusherインタフェースを注入したり、他のコンテナが依存する場所を注入したりすることができます.
use App\Contracts\EventPusher;
/**
* Create a new class instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
#コンテキストバインド(context binding)
Sometimes you may have two classes that utilize the same interface, but you wish to inject different implementations into each class. For example, when our system receives a new Order, we may want to send an event via PubNub rather than Pusher. Laravel provides a simple, fluent interface for defining this behavior:
2つのクラスが同じインタフェースを使用する必要がある場合がありますが、クラスごとに異なるインタフェースを注入して実装したい場合があります.たとえば、システムが新しい注文を受信した場合、Pusherの代わりにPubNuubを使用してメッセージを送信する必要があります.Laravelは、上記の動作を定義するための簡単なインタフェースを提供します.
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give('App\Services\PubNubEventPusher');
You may even pass a Closure to the give method:
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
->needs('App\Contracts\EventPusher')
->give(function () {
// Resolve dependency...
});
#ラベル
Occasionally, you may need to resolve all of a certain "category"of binding. For example, perhaps you are building a report aggregator that receives an array of many different
Report
interface implementations. After registering the Report
implementations, you can assign them a tag using the tag
method: バインド内のカテゴリを解析する必要がある場合があります.たとえば、Reportインタフェースを実装した異なる実装の配列を受信する必要がある要約レポートを構築しています.Reportのこれらのインプリメンテーションを登録した後、tagメソッドでラベルを付けることができます.
$this->app->bind('SpeedReport', function () {
//
});
$this->app->bind('MemoryReport', function () {
//
});
$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
Once the services have been tagged, you may easily resolve them all via the
tagged
method: これらのサービスがラベルを付けられるとtagged法で簡単に解析できます
$this->app->bind('ReportAggregator', function ($app) {
return new ReportAggregator($app->tagged('reports')); // ReportAggregator
});
#解析
There are several ways to resolve something out of the container. First, you may use the
make
method, which accepts the name of the class or interface you wish to resolve: コンテナから何かを解析する方法はいくつかあります.まず、makeメソッドを使用して、解析したいクラスやインタフェースの名前を受け入れることができます.
$fooBar = $this->app->make('FooBar');
Secondly, you may access the container like an array, since it implements PHP's
ArrayAccess
interface: 2つ目は、PHPのArrayAccessインタフェースを実現しているため、配列のようにコンテナを使用することができます.
$fooBar = $this->app['FooBar'];
Lastly, but most importantly, you may simply "type-hint"the dependency in the constructor of a class that is resolved by the container, including controllers , event listeners , queue jobs , middleware , and more. In practice, this is how most of your objects are resolved by the container.
The container will automatically inject dependencies for the classes it resolves. For example, you may type-hint a repository defined by your application in a controller's constructor. The repository will automatically be resolved and injected into the class:
最後に最も重要なのは、クラスのコンストラクタの中で「タイププロンプト」に依存するだけで、コンテナは解析後のクラスに自動的に注入されます.例えば、アプリケーションのコントローラでタイププロンプトでrepositoryエンティティクラスを提示し、エンティティクラスは自動的に解析されて注入されます.
<?php
namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
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)
{
//
}
}
#コンテナイベント
The service container fires an event each time it resolves an object. You may listen to this event using the
resolving
method: サービスコンテナが解析オブジェクトのイベントを発行するたびに、resolvingメソッドを使用してリスニングします.
$this->app->resolving(function ($object, $app) {
// Called when container resolves object of any type...
});
$this->app->resolving(function (FooBar $fooBar, $app) {
// Called when container resolves objects of type "FooBar"...
});
As you can see, the object being resolved will be passed to the callback, allowing you to set any additional properties on the object before it is given to its consumer.
解析されたオブジェクトは、閉パッケージメソッドに渡され、他のプロパティを設定できます.