Readouble

Laravel 5.0 サービスコンテナ

イントロダクションIntroduction

Laravelのサービスコンテナは、クラス間の依存を管理する強力な管理ツールです。依存注入というおかしな言葉は主に「コンストラクターか、ある場合にはセッターメソッドを利用し、あるクラスをそれらに依存しているクラスへ外部から注入する」という意味で使われます。The Laravel service container is a powerful tool for managing class dependencies. Dependency injection is a fancy word 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:

<?php namespace App\Handlers\Commands;

use App\User;
use App\Commands\PurchasePodcastCommand;
use Illuminate\Contracts\Mail\Mailer;

class PurchasePodcastHandler {

	/**
	 * メイラーの実装
	 */
	protected $mailer;

	/**
	 * 新しいインスタンスの生成
	 *
	 * @param  Mailer  $mailer
	 * @return void
	 */
	public function __construct(Mailer $mailer)
	{
		$this->mailer = $mailer;
	}

	/**
	 * ポッドキャストの購入
	 *
	 * @param  PurchasePodcastCommand  $command
	 * @return void
	 */
	public function handle(PurchasePodcastCommand $command)
	{
		//
	}

}

この例でPurchasePodcastコマンドハンドラーは、ポッドキャスト購入時にメールを送信する必要があります。そのため、メールを送信できるサービスを注入しています。サービスが外部から注入されているため、簡単に他の実装と交換できます。さらに「モック」したり、アプリケーションのテストを行うためにメーラーのダミー実装を作成したりするのも簡単に実現できます。In this example, the PurchasePodcast command handler 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.

Laravelのサービスコンテナを深く理解するのは、パワフルで大きなアプリケーションを構築することと同時に、Laravelコア自身に貢献するために重要なことです。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.

基本的な使用法Basic Usage

結合Binding

サービスコンテナへの登録は、ほぼ全てサービスプロバイダーの中で行われるでしょう。そのため以降のサンプルコードは、コンテナをプロバイダー内で使用するデモンストレーションになっています。しかし、例えばファクトリーのような、アプリケーションのどこか他の場所で、コンテナのインスタンスが必要になったら、Illuminate\Contracts\Container\Container契約をタイプヒントで指定すれば、コンテナのインスタンスが注入されます。もしくは、Appファサードでコンテナにアクセスすることもできます。Almost all of your service container bindings will be registered within service providers[/docs/{{version}}/providers], so all of these examples will demonstrate using the container in that context. However, if you need an instance of the container elsewhere in your application, such as a factory, you may type-hint the Illuminate\Contracts\Container\Container contract and an instance of the container will be injected for you. Alternatively, you may use the App facade to access the container.

基本的なリゾルバーの登録Registering A Basic Resolver

サービスプロバイダーの中でコンテナへアクセスするには、$this->appインスタンス変数を使用する必要があります。Within a service provider, you always have access to the container via the $this->app instance variable.

サービスコンテナへ依存を登録するには、多くの方法があります。この中には、クロージャーのコールバックやインターフェイスと実装の結合も含まれます。最初に、クロージャーのコールバックを説明しましょう。クロージャーを利用したリゾルバー(resolver:依存の解決ロジック、通常はインスンタンスの生成)は、キー(典型的な使用法ではクラス名)と値(インスタンス)を返すクロージャーをコンテナの中で登録します。There are several ways the service container can register dependencies, including Closure callbacks and binding interfaces to implementations. First, we'll explore Closure callbacks. A Closure resolver is registered in the container with a key (typically the class name) and a Closure that returns some value:

$this->app->bind('FooBar', function($app)
{
	return new FooBar($app['SomethingElse']);
});

シングルトンとして登録Registering A Singleton

場合により、コンテナに結合した何かを一度だけ依存解決したいことがあると思います。コンテナが何度呼び出されても、同じインスタンスが返されます。Sometimes, you may wish to bind something into the container that should only be resolved once, and the same instance should be returned on subsequent calls into the container:

$this->app->singleton('FooBar', function($app)
{
	return new FooBar($app['SomethingElse']);
});

存在するインスタンスをコンテナへ結合Binding An Existing Instance Into The Container

既に存在するオブジェクトのインスタンスをinstanceメソッドを用いて、コンテナに結合することもできます。指定されたインスタンスが、以降のコンテナで呼び出されるたびに返されます。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:

$fooBar = new FooBar(new SomethingElse);

$this->app->instance('FooBar', $fooBar);

依存解決Resolving

コンテナから何かの依存を解決して取り出すには、様々な方法が取れます。最初に、makeメソッドを使用してみましょう。There are several ways to resolve something out of the container. First, you may use the make method:

$fooBar = $this->app->make('FooBar');

コンテナはPHPのArrayAccessを実装していますので、次にコンテナへの「配列アクセス」を使ってみましょう。Secondly, you may use "array access" on the container, since it implements PHP's ArrayAccess interface:

$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, filters, and more. The container will automatically inject the dependencies:

<?php namespace 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)
	{
		//
	}

}

インターフェイスと実装の結合Binding Interfaces To Implementations

具象依存クラスの注入Injecting Concrete Dependencies

サービスコンテナーのとても強力な機能は、インターフェイスを指定された実装に結合することです。例えば、アプリケーションが、リアルタイムイベントを送受信するサービスであるPusher Webサービスと統合されているとしましょう。PusherのPHP DSKを使用していれば、クラスへPusherクライアントのインスタンスを注入することができます。A very powerful feature of the service container is its ability to bind an interface to a given implementation. For example, perhaps our application integrates with the Pusher[https://pusher.com] web service for sending and receiving real-time events. If we are using Pusher's PHP SDK, we could inject an instance of the Pusher client into a class:

<?php namespace App\Handlers\Commands;

use App\Commands\CreateOrder;
use Pusher\Client as PusherClient;

class CreateOrderHandler {

	/**
	 * Pusher SDKクライアントインスタンス
	 */
	protected $pusher;

	/**
	 * 新しい注文処理インスタンスの生成
	 *
	 * @param  PusherClient  $pusher
	 * @return void
	 */
	public function __construct(PusherClient $pusher)
	{
		$this->pusher = $pusher;
	}

	/**
	 * 指定されたコマンドの実行
	 *
	 * @param  CreateOrder  $command
	 * @return void
	 */
	public function execute(CreateOrder $command)
	{
		//
	}

}

この例の良い点は、クラス依存を外部から注入していることです。ですが、Pusher SDKときつく結びついた実装です。Pusher SDKに変更があったり、新しいイベントサービスへ全体を移行する決定を行うと、CreateOrderHandlerコードを変更しなくてはなりません。In this example, it is good that we are injecting the class dependencies; however, we are tightly coupled to the Pusher SDK. If the Pusher SDK methods change or we decide to switch to a new event service entirely, we will need to change our CreateOrderHandler code.

インターフェイスに対するプログラミングProgram To An Interface

イベント送信の変更に対して、CreateOrderHandlerを「分離」させるため、EventPusherインターフェイスとPusherEventPusher実装を定義することができます。In order to "insulate" the CreateOrderHandler against changes to event pushing, we could define an EventPusher interface and a PusherEventPusher implementation:

<?php namespace App\Contracts;

interface EventPusher {

	/**
	 * 新しいイベントを全クライアントにPushする
	 *
	 * @param  string  $event
	 * @param  array  $data
	 * @return void
	 */
	public function push($event, array $data);

}

このインターフェイスに対して、PusherEventPusher実装をコードし終えたら、次のようにサービスコンテナで登録します。Once we have coded our PusherEventPusher implementation of this interface, we can register it with the service container like so:

$this->app->bind('App\Contracts\EventPusher', 'App\Services\PusherEventPusher');

これはコンテナに対し、EventPusherの実装が必要になったら、PusherEventPusherを注入するように指示しています。This tells the container that it should inject the PusherEventPusher when a class needs an implementation of EventPusher. Now we can type-hint the EventPusher interface in our constructor:

	/**
	 * 新しい注文処理インスタンスの生成
	 *
	 * @param  EventPusher  $pusher
	 * @return void
	 */
	public function __construct(EventPusher $pusher)
	{
		$this->pusher = $pusher;
	}

コンテキストに合わせた結合Contextual Binding

時には、同じインターフェイスを使用した2つのクラスがあり、クラスごとに異なった実装を注入しなくてはならない場合もあるでしょう。例えば、システムが新しい注文(order)を受けた時は、Pusherの代わりに、PubNubを利用してイベントを送る必要がある場合です。Laravelは、このような振る舞いを定義できる、シンプルで読みやすいインターフェイスを提供しています。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[http://www.pubnub.com/] rather than Pusher. Laravel provides a simple, fluent interface for defining this behavior:

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give('App\Services\PubNubEventPusher');

タグ付けTagging

ある明確な「カテゴリー」の結合を全部解決する必要がある場合も存在すると思います。例えば、Reportインターフェイスの実装である、異なった多くの配列を受け取る、レポート収集プログラム(aggregator)を構築しているとしましょう。それらをtagメソッでタグ付けすることができます。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:

$this->app->bind('SpeedReport', function()
{
	//
});

$this->app->bind('MemoryReport', function()
{
	//
});

$this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');

サービスにタグを付けてしまえば、taggedメソッドで簡単に全部解決できます。Once the services have been tagged, you may easily resolve them all via the tagged method:

$this->app->bind('ReportAggregator', function($app)
{
	return new ReportAggregator($app->tagged('reports'));
});

アプリケーションでの実践Practical Applications

Laravelではアプリケーションの柔軟性とテスタビリティーを上げるため、サービスコンテナを利用できる箇所がたくさんあります。重要な一例は、コントローラーの依存解決時です。コントローラーは全てサービスコンテナを通じて解決されます。つまり、コントローラーのコンストラクターの中で、依存をタイプヒントで指定でき、それらは自動的に注入されます。Laravel provides several opportunities to use the service container to increase the flexibility and testability of your application. One primary example is when resolving controllers. All controllers are resolved through the service container, meaning you can type-hint dependencies in a controller constructor, and they will automatically be injected.

<?php namespace App\Http\Controllers;

use Illuminate\Routing\Controller;
use App\Repositories\OrderRepository;

class OrdersController extends Controller {

	/**
	 * 注文リポジトリーインスタンス
	 */
	protected $orders;

	/**
	 * コントローラーインスタンスの生成
	 *
	 * @param  OrderRepository  $orders
	 * @return void
	 */
	public function __construct(OrderRepository $orders)
	{
		$this->orders = $orders;
	}

	/**
	 * 全注文の表示
	 *
	 * @return Response
	 */
	public function index()
	{
		$orders = $this->orders->all();

		return view('orders', ['orders' => $orders]);
	}

}

この例では、OrderRepositoryクラスは自動的にコントローラーへ注入されます。つまりユニットテストを行う場合には、コンテナに「モック」のOrderRepositoryを結合して、苦労なくデータベース層のやりとりをスタブ化できるのです。In this example, the OrderRepository class will automatically be injected into the controller. This means that a "mock" OrderRepository may be bound into the container when unit testing[/docs/{{version}}/testing], allowing for painless stubbing of database layer interaction.

その他のコンテナ使用例Other Examples Of Container Usage

もちろん、前記の通り、Laravelでサービスコンテナにより依存解決されるクラスは、コントローラーだけではありません。ルートクロージャーやフィルター、キュージョブ、イベントリスナーなどでも依存をタイプヒントで指定できます。そうしたコンテキストでのコンテナ使用例は、各ドキュメントを参照してください。Of course, as mentioned above, controllers are not the only classes Laravel resolves via the service container. You may also type-hint dependencies on route Closures, filters, queue jobs, event listeners, and more. For examples of using the service container in these contexts, please refer to their documentation.

コンテナイベントContainer Events

リゾルバーリスナーの登録Registering A Resolving Listener

コンテナは、オブジェクトを依存解決した時に毎回イベントを発行します。このイベントは、resolvingを使用して、リッスンできます。The container fires an event each time it resolves an object. You may listen to this event using the resolving method:

$this->app->resolving(function($object, $app)
{
	// どんなタイプのものでもコンテナが依存解決した時に呼び出される…
});

$this->app->resolving(function(FooBar $fooBar, $app)
{
	// "FooBar"タイプのオブジェクトがコンテナにより依存解決された時に呼び出される…
});

依存解決されたオブジェクトが、コールバックに渡されます。The object being resolved will be passed to the callback.

章選択

Artisan CLI

設定

明暗テーマ
light_mode
dark_mode
brightness_auto システム設定に合わせる
テーマ選択
photo_size_select_actual デフォルト
photo_size_select_actual モノクローム(白黒)
photo_size_select_actual Solarized風
photo_size_select_actual GitHub風(青ベース)
photo_size_select_actual Viva(黄緑ベース)
photo_size_select_actual Happy(紫ベース)
photo_size_select_actual Mint(緑ベース)
コードハイライトテーマ選択

明暗テーマごとに、コードハイライトのテーマを指定できます。

テーマ配色確認
スクリーン表示幅
640px
80%
90%
100%

768px以上の幅があるときのドキュメント部分表示幅です。

インデント
無し
1rem
2rem
3rem
原文確認
原文を全行表示
原文を一行ずつ表示
使用しない

※ 段落末のEボタンへカーソルオンで原文をPopupします。

Diff表示形式
色分けのみで区別
行頭の±で区別
削除線と追記で区別

※ [tl!…]形式の挿入削除行の表示形式です。

テストコード表示
両コード表示
Pestのみ表示
PHPUnitのみ表示
OS表示
全OS表示
macOSのみ表示
windowsのみ表示
linuxのみ表示
和文変換

対象文字列と置換文字列を半角スペースで区切ってください。(最大5組各10文字まで)

本文フォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

コードフォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

保存内容リセット

localStrageに保存してある設定項目をすべて削除し、デフォルト状態へ戻します。

ヘッダー項目移動

キーボード操作