LoginSignup
43
39

More than 5 years have passed since last update.

laravelのコンテナとりまとめ

Last updated at Posted at 2015-04-15

内部挙動を押さえときたかったので。一部日本語が変なのはご愛嬌

目的

  • コンテナ名前解決の仕組みをたどる
  • コンストラクタ自動注入の仕組みをたどる

サービスコンテナ

オブジェクトのかご。オブジェクトに名前つけて突っ込んで後から取り出す。都合のいいグローバル変数みたいな(使い方をしてはイケない)。

突っ込みたい人向け

インスタンスを突っ込む

オブジェクトを作ってから突っ込む。

$fooBar = new FooBar(new SomethingElse);

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

オブジェクトの作り方を突っ込む

オブジェクトの作り方だけ。取り出す人が作ればええやんスタイル。

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

オブジェクトの作り方を突っ込む(節約指向)

オブジェクトの作り方だけ。一番最初に取り出した人が作って、後の人は最初の人が作ったやつをもらう。

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

欲しい人向け

決めた名前で取り出す。

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

ここまでがざっくり使い方。

コンテナへの登録:お名前と本体

サービスコンテナには 登録時の名前 $abstract と、それに紐づく処理$concrete とがある。

bindとかsingletonでいうところの第一引数が$abstractで第二引数が$concrete。ちなみにsingletonbindの糖衣構文でしか無く処理はほぼ同じ(sharedフラグを立てるだけ)。

    /**
     * Register a shared binding in the container.
     *
     * @param  string  $abstract
     * @param  \Closure|string|null  $concrete
     * @return void
     */
    public function singleton($abstract, $concrete = null)
    {
        $this->bind($abstract, $concrete, true);
    }

bindに渡された$concreteは、どのような値であっても内部的に全てクロージャに変換される。

makeによる取り出しで何がおこるか

$fooBar = $app->make($abstract);

は、内部的には

$fooBar = $app->build($concrete);

に変換される。
(かなりざっくり端折った。実際にはsingletonキャッシュとかその辺が色いろある。)

bindにより紐付けられた$abstractによるコールmake($abstract)は、紐づけられた$concreteによるコールbuild($concrete)となる。
この場合、bindによる$concreteはクロージャに変換される、のルールによりbindの引数は必ずクロージャである。

紐付のない$abstractによるコールmake($abstract)は、build($abstract)に変換され、これもまたbindメソドへと渡される。
このケースの引数はクロージャとは限らない。

build の実装

buildはクロージャを受け取って、それを実行する。引数としてコンテナ自信を渡すため、クロージャでは第一引数に$appが取れる。

これだけであれば非常にシンプルなのだが、ややこしいのがクロージャでないケース。

$concretebind時に自動的にクロージャに変換される。この変換されるクロージャは概ねこんな感じである。

    function($app) use ($concrete)
    {
        return $app->build($concrete);
    }

クロージャと言えどbuildをラップしているだけの構成。
自動でクロージャに変換された非クロージャの$concreteは、一旦は自動生成されたクロージャとしてbuildに解釈されても、次のステップで元の文字列としてbuild($concrete)される。

buildの引数に文字列(クラス名)を与えた場合、当該クラスのインスタンスを生成する。

これはリフレクションを用いたlaravelっぽいコンストラクタ注入自動解決のあれでインスタンスを生成するマンで、タイプヒントに基づくコンテナからのクラス取り出しを連鎖的に自動で行ってくれるもの。

このような理由でコンテナに突っ込んだクラス名は、自動的にコンストラクタ注入が適用されるというわけ。

つまりコンテナ外でもbuildメソドさえコールしてやれば、勝手にコンストラクタ注入してくれる。あまりオススメはしないけど。

43
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
43
39