Readouble

Laravel 5.2 サービスコンテナ

イントロダクションIntroduction

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

<?php

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

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.

結合Binding

サービスコンテナへの登録は、ほぼ全てサービスプロバイダの中で行うことになります。そのため以降のサンプルコードは、コンテナをプロバイダ内で結合するデモンストレーションになっています。しかし、インターフェイスに依存していなければコンテナにクラスを結合する必要はありません。コンテナはそのような「具象」オブジェクトはPHPのリフレクションサービスを使用し、自動的に依存を解決しますので、オブジェクトの生成方法をコンテナに指示する必要はありません。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, 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 on how to build these objects, since it can automatically resolve such "concrete" objects using PHP's reflection services.

サービスプロバイダの中からは、いつでも$this->appインスタンス変数によりコンテナにアクセスできます。bindメソッドへ登録したいクラス名かインターフェイス名と、クラスのインスタンスを返す「クロージャ」を引数として渡せば、結合を登録できます。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:

$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.

シングルトン結合Binding A Singleton

singletonメソッドは、クラスやインターフェイスが一度だけ依存解決されるようにコンテナに登録します。以降コンテナから呼び出されると同じインスタンスが返されます。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:

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

インスタンス結合Binding Instances

既に存在するオブジェクトのインスタンスを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);

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

サービスコンテナーのとても強力な機能は、インターフェイスを指定された実装に結合できることです。たとえばEventPusherインターフェイスとRedisEventPusher実装があるとしましょう。このインターフェイスのRedisEventPusherを実装し終えたら、サービスコンテナに登録できます。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:

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

これはつまり、EventPusherの実装クラスが必要な時、コンテナはRedisEventPusherを注入するということです。ではコンストラクタか、もしくはサービスコンテナが依存を注入できる場所で、EventPusherインターフェイスをタイプヒントしてみましょう。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:

use App\Contracts\EventPusher;

/**
 * 新しいインスタンスの生成
 *
 * @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');

giveメソッドにはクロージャを渡すことも可能です。You may even pass a Closure to the give method:

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('App\Contracts\EventPusher')
          ->give(function () {
                  // 依存の解決…
              });

プリミティブ結合Binding Primitives

クラスにより依存注入されたインスタンスを受け取ることもあるでしょうし、さらに整数のようなプリミティブな値を挿入する必要も起きるでしょう。必要なクラスのコンテキストによる結合を使用すれば簡単です。Sometimes you may have a class that receives some injected classes, but also needs an injected primitive value such as an integer. You may easily use contextual binding to inject any value your class may need:

$this->app->when('App\Handlers\Commands\CreateOrderHandler')
          ->needs('$maxOrderCount')
          ->give(10);

タグ付けTagging

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

依存解決Resolving

コンテナから何かを依存解決する方法は、数多くあります。最初に解決したいクラスかインターフェイスの名前をmakeメソッドに指定することができます。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:

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

次に、コンテナはPHPのArrayAccessインターフェイスを実装していますので、配列のようにアクセスできます。Secondly, you may access the container like an array, 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[/docs/{{version}}/controllers], event listeners[/docs/{{version}}/events], queue jobs[/docs/{{version}}/queues], middleware[/docs/{{version}}/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:

<?php

namespace App\Http\Controllers;

use App\Users\Repository as UserRepository;

class UserController extends Controller
{
    /**
     * Userリポジトリインスタンス
     */
    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)
    {
        //
    }
}

コンテナイベントContainer Events

コンテナはオブジェクトの依存解決時に毎回イベントを発行します。このイベントは、resolvingを使用して購読できます。The service 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(FooBar::class, function (FooBar $fooBar, $app) {
    // "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.

章選択

設定

明暗テーマ
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に保存してある設定項目をすべて削除し、デフォルト状態へ戻します。

ヘッダー項目移動

キーボード操作