如何实现DI容器?

时间:2014-05-10 16:16:43

标签: php oop design-patterns service containers

我一直在询问,如果在控制器中创建模型层的实例是错误的,即使它隐藏在这样的工厂后面:

parent::getServiceFactory()->create('Car');

我被告知使用依赖注入容器来初始化我的控制器。昨晚我一直在谷歌搜索,昨晚,我明白依赖注入容器(DiC)用于创建一个对象的实例,并将所需的对象注入其中,而无需在路由器中手动执行 - 也许我只是误解了概念

我已阅读此帖How to build a PHP Dependency Injection Container,它显示以下代码行:

$ioc->register('database', new DatabaseServiceProvider($host, $user, $pass))

现在,我假设$host, $user, $pass只是字符串变量,现在如果我想将对象传递给控制器​​,我怎样才能动态地知道它需要注入哪些对象?

添加像这样的类型数组是否正确?:

$container->register('SomeController', array('Namespace\to\Model1', 'Namespace\to\Model2'));

然后容器寄存器将创建一个SomeController的对象,它将具有Model1,Model2对象

这样做有误吗?在这种情况下使用DI的正确方法是什么?也是Domain对象&数据映射器模型层的一部分?

或者在应用程序加载时初始化容器中的所有控制器对象是正确的,那么我可以轻松地使用任何控制器吗?

1 个答案:

答案 0 :(得分:0)

  

我被告知使用A依赖注入容器进行初始化   我的控制人员。昨晚我一直在谷歌上搜索,我   了解依赖注入容器(DiC)用于创建   一个对象的实例,并将所需的对象注入其中。

这是正确的。

  

我已经阅读了这篇文章如何构建PHP依赖注入   容器

停在那儿。答案显示如何构建容器 - 它显示了如何构建service locator。这两者之间存在巨大差异:

  • 服务定位器就像一个键/值存储:你将命名的东西放在里面,然后你按名称要求它们,定位器将它们返回给你。
  • 注射容器就像一个工厂:你要求它生产一些产品并为你生产它。 产品的具体细节可以从完全不透明到完全可以指定。

在外行人看来,服务定位器可以做到这一点:

class Perishable
{
    public function __construct(DateTime $expirationDate) { ... }
}

$locator->set('milk', new Perishable(new DateTime());
$milk = $locator->get('milk');

但是,与注射容器相比,它不能这样做:

$milk = $container->build(Perishable::class); // ::class is a PHP 5.5 feature

注入容器能够自行确定 Perishable依赖DateTime并解决该依赖关系。这是以递归的方式发生的,并且理解了所有" leaf"依赖关系可以实例化。在这种情况下,DateTime很容易实例化,因为它是一个具有可以无参数运行的构造函数的具体类;在其他情况下,您必须通过告诉容器如果遇到无法直接实例化的依赖关系该怎么做来提供帮助,例如, Iterator

  

现在,我认为$host$user$pass只是字符串变量,现在如果我   想要将对象传递给控制器​​,我怎样才能动态地知道哪些   它需要注入的物体?

我们现在已经达到了实施部分:您如何知道Perishable需要DateTime,以及如何创建DateTime

您可以使用reflection

执行此操作
$class = new ReflectionClass('Perishable');
$constructor = $class->getConstructor();
$arguments = [];
foreach ($constructor->getParameters() as $parameter) {
    $argumentClass = $parameter->getClass();
    $arguments[] = $argumentClass->newInstance();
}

$result = $class->newInstanceArgs($arguments);

这是可以实例化上面给出的Perishable的准系统代码,但当然它会在更一般的情况下严重失败(还有更多你需要妥善处理的事情,例如递归解决构造函数参数)。

  

添加像这样的类型数组是否正确?

不,因为你必须违反DRY:SomeController的依赖关系既会被指定为构造函数定义的一部分,也会被注册到容器或定位器中。

  

或者是否正确初始化容器中的所有控制器对象   应用程序加载,然后我可以轻松使用任何控制器?

它根本不对,如上所述,你正在使用" container"实际上,你有一个服务定位器的心理图片。通常,服务定位器具有许多缺点,即注射容器不具有这些缺点。在这种情况下,您应该使用适当的容器。

相关问题