Php 如何实现DI容器?

Php 如何实现DI容器?,php,oop,design-patterns,service,containers,Php,Oop,Design Patterns,Service,Containers,我一直在问,在控制器中创建模型层的实例是否错误,即使它隐藏在这样的工厂后面: parent::getServiceFactory()->create('Car'); 我被告知使用依赖项注入容器来初始化控制器。我整晚都在谷歌上搜索,昨晚,我了解到依赖注入容器(DiC)用于创建对象的实例,并将所需的对象注入其中,而无需在路由器中手动操作-也许我只是误解了这个概念 我读过这篇文章,它显示了以下代码行: $ioc->register('database', new DatabaseServ

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

parent::getServiceFactory()->create('Car');
我被告知使用依赖项注入容器来初始化控制器。我整晚都在谷歌上搜索,昨晚,我了解到依赖注入容器(DiC)用于创建对象的实例,并将所需的对象注入其中,而无需在路由器中手动操作-也许我只是误解了这个概念

我读过这篇文章,它显示了以下代码行:

$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
的正确方法是什么?域对象和数据映射器是否也是模型层的一部分

或者在应用程序加载时初始化容器中的所有控制器对象是否正确,这样我就可以轻松使用任何控制器了

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

这是正确的

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

停在那里。这个答案并没有说明如何构建一个容器,而是说明了如何构建一个容器。两者之间有着巨大的区别:

  • 服务定位器类似于键/值存储:您将命名的东西放入其中,然后按名称请求它们,定位器将它们返回给您
  • 注射容器就像一个工厂:你要求它生产一些东西,它为你生产。产品如何创建的细节可以是完全不透明的,也可以是完全可指定的
用外行的话说,服务定位器可以做到这一点:

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
注入容器能够自行确定
易腐
日期时间
有依赖关系,并解决该依赖关系。这是递归发生的,需要理解的是,所有“叶”依赖项都可以实例化。在这种情况下,
DateTime
很容易实例化,因为它是一个具体的类,具有可以无参数运行的构造函数;在其他情况下,如果容器遇到无法直接实例化的依赖项(例如,
迭代器
),您必须通过告诉容器该怎么做来提供帮助

现在,我假设
$host
$user
$pass
只是字符串变量,如果我 要将对象传递给控制器,如何动态地知道 它需要注入的对象

我们现在已经谈到了实现部分:您如何知道
易腐
需要
日期时间
,以及如何创建该
日期时间

您可以使用以下方法进行此操作:

这是一个简单的代码,可以实例化上面给出的
易腐的
,但在更一般的情况下,它当然会失败得很厉害(需要正确处理的还有很多,例如递归解析构造函数参数)

添加这样的类型数组正确吗

否,因为您必须违反DRY:将指定
SomeController
的依赖项作为其构造函数定义的一部分,并将其注册到容器或定位器中

或者当 应用程序加载,那么我可以轻松使用任何控制器吗


这一点都不正确,正如上面所解释的,您使用的是“容器”这个词,而实际上您在脑海中看到了一个服务定位器。一般来说,服务定位器有许多注入容器没有的缺点。在这种情况下,您应该使用合适的容器。

在尝试实际使用DI容器之前,您应该首先了解DI容器是什么以及为什么要使用它。
$class = new ReflectionClass('Perishable');
$constructor = $class->getConstructor();
$arguments = [];
foreach ($constructor->getParameters() as $parameter) {
    $argumentClass = $parameter->getClass();
    $arguments[] = $argumentClass->newInstance();
}

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