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 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。