ディペンデンシー・インジェクション

Aura.Diは以下の機能があるデペンデンシーテンテナシステムです。

  • コンストラクター&セッターインジェクション

*タイプヒントされたコンストラクタ引数の明示的、非明示的な自動解決

  • インターフェイスとトレイトによるコンフィギュレーション

  • コンストラクタ引数とセッターメソッドの値の継承

  • サービス、値、インスタンスの遅延評価

  • インスタンスファクトリー

この章では簡単にするためにコンストラクターとセッタージェクションを取り上げます。 Aura.Di documentationを読むことをお勧めします。

サービスのセットと取得

“サービス”は_コンテナ_にユニークな名前をつけて格納されるオブジェクトです。 名付けられたサービスはいつでも get() することができ、いつでも同じオブジェクトのインスタンスが取得できます。

<?php
// Exampleクラスを定義
class Example
{
    // ...
}

// サービスをセットする
$di->set('service_name', new Example);

// サービスを取得する
$service1 = $di->get('service_name');
$service2 = $di->get('service_name');

// 2つのサービスは同一
var_dump($service1 === $service2); // true
?>

この使い方はサービスをセットしたときと同じ_Example_インスタンスをつくるのには素晴らしい、しかしセットした時でなく、取得する時のインスタンスが欲しい場合もあります。

The technique of delaying instantiation until get() time is called “lazy loading.” To lazy-load an instance, use the lazyNew() method on the Container and give it the class name to be created: このテクニックは

<?php
// 遅延評価されるインスタンスとしてサービスをセットする
$di->set('service_name', $di->lazyNew('Example'));
?>

Now the service is created only when we we get() it, and not before. This lets us set as many services as we want, but only incur the overhead of creating the instances we actually use. サービスはあらかじめつくられるものではなく、get()の時に作られるようになりました。 実際に使うときだけオーバーヘッドがかかります。

コンストラクターインジェクション

_コンテナ_から新しいオブジェクトを生成するときに、様々な方法でコンストラクタ引数にインジェクト(セット)する必要があります。

引数のデフォルト値

$di->params配列を使って_Container_にデフォルト値を定義することができます。

コンストラクタ引数を必要とするクラスをみてみましょう。

<?php
class ExampleWithParams
{
    protected $foo;
    protected $bar;
    public function __construct($foo, $bar)
    {
        $this->foo = $foo;
        $this->bar = $bar;
    }
}
?>

この場合、$di->lazyNew('ExampleWithParams')を使ってサービスをセットするとインスタンス生成は失敗します。$foo引数が必要で_Container_はどうやって値を用意するのか分かりません。

To remedy this, we tell the Container what values to use for each ExampleWithParams constructor parameter by name using the $di->params array:

これに対処するためには、 _ExampleWithParams_クラスのコンストラクタ引数に$di->params配列を使って_Container_クラスに伝えます。

<?php
$di->params['ExampleWithParams']['foo'] = 'foo_value';
$di->params['ExampleWithParams']['bar'] = 'bar_value';
?>

Now when a service is defined with $di->lazyNew('ExampleWithParams'), the instantiation will work correctly. Each time we create an ExampleWithParams instance through the Container, it will apply the $di->params['ExampleWithParams'] values.

サービスが$di->lazyNew('ExampleWithParams')で定義されると、正しくインスタンス生成されます。 _Container_を通じて_ExampleWithParams_インスタンスを作るたびに$di->params['ExampleWithParams']の値が適用されます。

特定インスタンスの引数値

特定の新しいインスタンスのために$di->paramsのデファルトの値を上書きしたいときには、 $params配列の2番目の引数でlazyNew()をデフォルトの値にマージします。

例)

<?php
$di->set('service_name', $di->lazyNew(
    'ExampleWithParams',
    array(
        'bar' => 'alternative_bar_value',
    )
));
?>

$foo引数をデフォルトのままにしますが、_ExampleWithParams_がインスタンス化されるときに$bar引数の値が上書きされます。

引数の値として遅延評価されるサービス

クラスは他のサービスを引数として必要とすることがあります。 例えば、以下のクラスはデータベース接続が必要です。

<?php
class ExampleNeedsService
{
    protected $db;
    public function __construct($db)
    {
        $this->db = $db;
    }
}
?>

共有されるサービスとして引数にインジェクトするためには$di->lazyGet()を使います。 その場合_ExampleNeedsService_オブジェクトがつくられるまでサービスオブジェクトはつくられません。

<?php
$di->params['ExampleNeedsService']['db'] = $di->lazyGet('db_service');
?>

これはサービスが必要とされる時まで作成されません。(もしサービスが必要でなければ生成されません)

セッターインジェクション

コンストラクターインジェクションに加えてセッターインジェクションもサポートします。

セッターメソッドの値

_Container_が新しいオブジェクトのインスタンスを作成したあとに、特定のメソッドに特定の値を$di->setter配列に渡して呼ぶことができます。 例えば以下のようなクラスを考えてみます。

<?php
class ExampleWithSetter
{
    protected $foo;

    public function setFoo($foo)
    {
        $this->foo = $foo;
    }
}
?>

We can specify that, by default, the setFoo() method should be called with a specific value after construction like so:

setFoo()メソッドはコンストラクタの後に特定の値で呼ばれれます。

<?php
$di->setter['ExampleWithSetter']['setFoo'] = 'foo_value';
?>

値は何でも有効です。リテラルやlazyNew()lazyGet()を呼ぶことなどです。

しかしながらauto-resolutioんはセッターメソッドには適用できません なぜなら、これは_Container_がどのメソッドがセッターメソッドで、どれが”普通の”メソッドか分からないためです。

明示的に定義されたセッターメソッドに限って利用できます。

インスタンスに特定されたセッター値

コンストラクターインジェクションで行ったように、特定のデフォルトの値をセッターインジェクションでも指定することができます。 三番の引数に$di->lazyNew()で指定します。

例)

<?php
$di->set('service_name', $di->lazyNew(
    'ExampleWithSetters',
    array(), // no $params overrides
    array(
        'setFoo' => 'alternative_foo_value',
    )
));
?>