4.5. Definition extensions and overriding
定义扩展和覆盖
一个简单的应用程序通常使用一个或两个定义源:自动装配 (或注解) + 定义文件/数组。
但是,在更复杂的应用程序或模块化系统中,您可能希望拥有多个定义文件 (例如:每个模块/插件/…都有其定义文件)。在这种情况下,PHP-DI提供了一个清晰而强大的系统来重写/扩展定义。
定义源的优先级
从最低优先级到最高优先级:
- 自动装配(如果启用)
- 注解(如果启用)
- PHP definitions (文件或数组)中定义的顺序
- 使用
$container->set()
在容器中直接添加定义
示例
class Foo
{
public function __construct(Bar $param1)
{
}
}
PHP-DI 会使用自动装配注入 Bar
实例,因为注解有更高的优先级,因此我们可以使用注解进行覆盖:
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
,因为它无法通过自动装配猜测注入(无类型提示)。$ param1
则不受影响,并且已自动注入。
请注意, DI\autowire()
, 与 DI\create()
一样, 不允许扩展定义。它仅允许自定义自动装配的完成方式。在下面的示例中,第二个定义将完全覆盖第一个定义:
return [
Database::class => DI\autowire()
->constructorParameter('host', '192.168.34.121'),
];
return [
Database::class => DI\autowire()
->constructorParameter('port', 3306),
];
数组
你可以使用DI\add()
将条目添加到另一个文件/数组定义的阵列中:
return [
'array' => [
DI\get(Entry::class),
],
];
return [
'array' => DI\add([
DI\get(NewEntry::class),
]),
];
解析后,array
将包含2个条目。 如果您忘记使用DI \ add()
,则前面array
的值将被完全覆盖!
请注意,即使之前未声明array
,也可以使用DI \ add()
。
装饰器
您可以使用DI \ decorate()
装饰对象:
return [
ProductRepository::class => function () {
return new DatabaseRepository();
},
];
return [
ProductRepository::class => DI\decorate(function ($previous, ContainerInterface $c) {
//将数据库仓库包装在缓存代理中
return new CachedRepository($previous);
}),
];
可调用对象的第一个参数是先前定义返回的实例(即我们要修饰的实例),第二个参数是容器。
您可以对任何先前的定义(工厂,对象,值,环境变量等)使用DI \ decorate()
。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。