こんにちは。よっしーです(^^)
今日は、PHP-DIにおけるインジェクション定義の拡張とオーバーライドについてご紹介します。
背景
PHP-DIに触れる機会がありましたので、PHP-DIにおけるインジェクションの定義について備忘として残しました。
詳細は下記の公式サイトをご覧ください。
はじめに
単純なアプリケーションでは、通常1つまたは2つの定義ソースを利用します:(属性を使用した)オートワイヤリング + 定義ファイル/配列。
しかし、より複雑なアプリケーションやモジュラーシステムでは、複数の定義ファイル(モジュール/バンドル/プラグインごとに1つずつなど)を持ちたい場合があります。この場合、PHP-DIは定義をオーバーライドおよび/または拡張するための明確で強力なシステムを提供します。
定義ソースの優先順位
優先順位(低い順から高い順):
- オートワイヤリング(有効な場合)
- 属性(有効な場合)
- 追加された順序でのPHP定義(ファイルまたは配列)
- $container->set()でコンテナに直接追加された定義
例
class Foo
{
public function __construct(Bar $param1)
{
}
}
PHP-DIは、オートワイヤリングを使用してBarのインスタンスを注入します。ただし、属性は優先順位が高く、これを使用して定義をオーバーライドできます:
use DI\Attribute\Inject;
class Foo
{
#[Inject(['my.specific.service'])]
public function __construct(Bar $param1)
{
}
}
ファイルベースの定義を使用して、属性とオートワイヤリングをオーバーライドすることもできます:
return [
'Foo' => DI\create()
->constructor(DI\get('another.specific.service')),
// ...
];
もし別の定義ファイルがある場合(このファイルよりも後に登録された場合)、定義を再びオーバーライドできます。
定義の拡張
オブジェクト
DI\create()は、以前の定義やオートワイヤリングすら完全に上書きします。他の定義を拡張することはできません。拡張したい場合は、以下の「デコレータ」セクションを参照してください。
オートワイヤリング(属性の有無にかかわらず)を使用してオブジェクトをビルドする場合、DI\autowire()を使用して特定のパラメータをオーバーライドできます。
class Foo
{
public function __construct(Bar $param1, $param2)
{
}
}
return [
Foo::class => DI\autowire()
->constructorParameter('param2', 'Hello!'),
];
この例では、オートワイヤリング定義を拡張して、$param2を設定しています。$param2はオートワイヤリングを通じて推測できないため(型ヒントがない)、拡張が必要です。一方、$param1は影響を受けずにオートワイヤリングされます。
DI\autowire()もDI\create()同様、定義を拡張することはできません。オートワイヤリングがどのように行われるかをカスタマイズするだけです。以下の例では、2つ目の定義が最初の定義を完全に上書きします。
return [
Database::class => DI\autowire()
->constructorParameter('host', '192.168.34.121'),
];
return [
Database::class => DI\autowire()
->constructorParameter('port', 3306),
];
配列(Arrays)
他のファイル/配列で定義された配列にエントリを追加するには、DI\add()ヘルパーを使用できます。
return [
'array' => [
DI\get(Entry::class),
],
];
return [
'array' => DI\add([
DI\get(NewEntry::class),
]),
];
解決されると、配列には2つのエントリが含まれます。DI\add()を使用し忘れると、配列全体が完全に上書きされます!
注意:配列が以前に宣言されていなくても、DI\add()を使用できます。
ただし、DI定義内の配列に対しては、再帰的には動作しません。つまり、配列内に配列を含むエントリを持つことはできません。
return [
'array' => [
'subarray' => [DI\get(Entry::class)],
],
];
DI\add()を使用してサブ配列に要素を追加することはできません。
デコレータ(Decorators)
DI\decorate()を使用してオブジェクトをデコレートできます。
return [
ProductRepository::class => function () {
return new DatabaseRepository();
},
];
return [
ProductRepository::class => DI\decorate(function ($previous, ContainerInterface $c) {
// データベースリポジトリをキャッシュプロキシでラップ
return new CachedRepository($previous);
}),
];
呼び出し可能な関数の最初のパラメータは、前の定義によって返されるインスタンスです(つまり、デコレートしたいインスタンス)。2番目のパラメータはコンテナです。
DI\decorate()は、ファクトリだけでなく、オブジェクト、値、環境変数など、あらゆる種類の前の定義に対して使用できます。
おわりに
今日は、PHP-DIにおけるインジェクション定義の拡張とオーバーライドについてご紹介しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント