PHP-DI:创建与自动装配与获取。或者如何正确地将接口映射到定义提供的实现
PHP-DI: create vs. autowire vs. get. Or how to correctly map an interface to an implementation provided by a definition
对于 Web MVC 中的 PHP-DI 容器,我为路由器准备了以下定义:
return [
'router' => function (ContainerInterface $c) {
//...
return new Router(...);
}
];
现在我想将接口 (MyLib\Routing\RouterInterface
) 映射到 'router'
条目提供的实现。在 PHP-DI 文档中,我找到了实现此目的的三种方法。像这样:
RouterInterface::class => DI\create('router')
RouterInterface::class => DI\autowire('router')
RouterInterface::class => DI\get('router')
当我应用第三个选项时,一切正常,例如我可以检索接口条目:
$router = $container->get(RouterInterface::class);
var_dump($router);
但是,当我尝试前两个选项时,我收到错误消息:
(1/1) InvalidDefinition
Entry "MyLib\Routing\RouterInterface" cannot be resolved: the class doesn't exist
Full definition:
Object (
class = #UNKNOWN# router
lazy = false
)
所以我想问一下:请您解释一下,在这种情况下,这三个选项之间有什么区别?
谢谢
完成已接受的答案:
@MatthieuNapoli 的回答是正确的。我会用以下结论来完成它——基于我运行(见下文)的测试。
结论:
辅助函数 create()
和 autowire()
不以任何方式引用容器中的条目。他们接收一个 class 名称作为参数,并确保 class 的对象是 NEWLY 创建的(一次)。即使现有容器定义的名称与 class 名称相同,并且即使该条目已经创建了相同类型的对象,也会发生这种情况。
只有辅助函数 get()
引用容器条目,而不是 class 名称(正如 Matthieu 已经亲切介绍的那样)。
测试:
1) 我定义了以下 class:
<?php
namespace Test;
class MyTestClass {
public function __construct($input = NULL) {
if (empty($input)) {
$input = 'NO INPUT';
}
echo 'Hello from MyTestClass. Input is: ' . $input . '<br/>';
}
}
2) 我定义了以下容器条目:
return [
'Test\MyTestClass' => function (ContainerInterface $c) {
return new Test\MyTestClass('12345');
},
'my.test.entry.for.create' => DI\create('Test\MyTestClass'),
'my.test.entry.for.autowire' => DI\autowire('Test\MyTestClass'),
'my.test.entry.for.get' => DI\get('Test\MyTestClass'),
];
3) 我执行了以下代码:
<?php
$myTestEntryFor_MyTestClass = $container->get('Test\MyTestClass');
$myTestEntryFor_Create = $container->get('my.test.entry.for.create');
$myTestEntryFor_Autowire = $container->get('my.test.entry.for.autowire');
/*
* This prints nothing, because an object of type "MyTestClass" was
* already created by the container definition "'Test\MyTestClass'".
*/
$myTestEntryFor_Get = $container->get('my.test.entry.for.get');
4) 我收到了以下结果:
Hello from MyTestClass. Input is: 12345
Hello from MyTestClass. Input is: NO INPUT
Hello from MyTestClass. Input is: NO INPUT
我邀请您查看 functions.php 中那些函数的 phpdoc。
RouterInterface::class => DI\create('router')
这意味着 create
router
class:PHP class 不存在。
RouterInterface::class => DI\autowire('router')
这意味着 autowire
router
class(同样不存在)。
RouterInterface::class => DI\get('router')
这意味着“当我请求 RouterInterface::class
return router
条目时。请注意 get()
采用容器条目名称,而不是 class名字.
对于 Web MVC 中的 PHP-DI 容器,我为路由器准备了以下定义:
return [
'router' => function (ContainerInterface $c) {
//...
return new Router(...);
}
];
现在我想将接口 (MyLib\Routing\RouterInterface
) 映射到 'router'
条目提供的实现。在 PHP-DI 文档中,我找到了实现此目的的三种方法。像这样:
RouterInterface::class => DI\create('router')
RouterInterface::class => DI\autowire('router')
RouterInterface::class => DI\get('router')
当我应用第三个选项时,一切正常,例如我可以检索接口条目:
$router = $container->get(RouterInterface::class);
var_dump($router);
但是,当我尝试前两个选项时,我收到错误消息:
(1/1) InvalidDefinition
Entry "MyLib\Routing\RouterInterface" cannot be resolved: the class doesn't exist
Full definition:
Object (
class = #UNKNOWN# router
lazy = false
)
所以我想问一下:请您解释一下,在这种情况下,这三个选项之间有什么区别?
谢谢
完成已接受的答案:
@MatthieuNapoli 的回答是正确的。我会用以下结论来完成它——基于我运行(见下文)的测试。
结论:
辅助函数 create()
和 autowire()
不以任何方式引用容器中的条目。他们接收一个 class 名称作为参数,并确保 class 的对象是 NEWLY 创建的(一次)。即使现有容器定义的名称与 class 名称相同,并且即使该条目已经创建了相同类型的对象,也会发生这种情况。
只有辅助函数 get()
引用容器条目,而不是 class 名称(正如 Matthieu 已经亲切介绍的那样)。
测试:
1) 我定义了以下 class:
<?php
namespace Test;
class MyTestClass {
public function __construct($input = NULL) {
if (empty($input)) {
$input = 'NO INPUT';
}
echo 'Hello from MyTestClass. Input is: ' . $input . '<br/>';
}
}
2) 我定义了以下容器条目:
return [
'Test\MyTestClass' => function (ContainerInterface $c) {
return new Test\MyTestClass('12345');
},
'my.test.entry.for.create' => DI\create('Test\MyTestClass'),
'my.test.entry.for.autowire' => DI\autowire('Test\MyTestClass'),
'my.test.entry.for.get' => DI\get('Test\MyTestClass'),
];
3) 我执行了以下代码:
<?php
$myTestEntryFor_MyTestClass = $container->get('Test\MyTestClass');
$myTestEntryFor_Create = $container->get('my.test.entry.for.create');
$myTestEntryFor_Autowire = $container->get('my.test.entry.for.autowire');
/*
* This prints nothing, because an object of type "MyTestClass" was
* already created by the container definition "'Test\MyTestClass'".
*/
$myTestEntryFor_Get = $container->get('my.test.entry.for.get');
4) 我收到了以下结果:
Hello from MyTestClass. Input is: 12345
Hello from MyTestClass. Input is: NO INPUT
Hello from MyTestClass. Input is: NO INPUT
我邀请您查看 functions.php 中那些函数的 phpdoc。
RouterInterface::class => DI\create('router')
这意味着 create
router
class:PHP class 不存在。
RouterInterface::class => DI\autowire('router')
这意味着 autowire
router
class(同样不存在)。
RouterInterface::class => DI\get('router')
这意味着“当我请求 RouterInterface::class
return router
条目时。请注意 get()
采用容器条目名称,而不是 class名字.