【问题标题】:Why to use Dependency Injection components in PHP frameworks为什么在 PHP 框架中使用依赖注入组件
【发布时间】:2015-05-08 17:14:51
【问题描述】:
当我第一次看到 PHP-DI、Symfony2 DI 等依赖注入组件时,我发现有一种方法可以自动将任何类的实例注入到任何一个实例中。
所以
1.在根类中创建实例,如$foo = new Foo()
2. 然后我可以在任何对象(如全局单例)中使用此实例,而无需传递对我要调用的类的构造函数或方法的引用。
但我发现,基本上我可以通过两种方式使用依赖注入
1.将实例的引用传递给构造函数
2. 创建所有对象所在的容器。这个容器可以注入其他类,但是“不推荐”。
由于这两种方法都可以在纯 PHP 中轻松完成,第一种很清楚,第二种可以通过静态属性解决,那么为什么要使用 PHP-DI 或 Symfony2 来完成这项工作呢?
【问题讨论】:
标签:
php
symfony
dependency-injection
singleton
php-di
【解决方案1】:
为什么要在单例模式上使用依赖注入?
假设我们有一个名为 DatabaseConnection 的 Singleton 对象,它为我们包装了一个到 MySQL 数据库的连接,并做了一些其他巧妙的事情,谁知道呢。因为重用代码是一件好事,所以我们在很多项目中都会用到这个对象。
如果在某个时候我们决定将我们的一个项目从 MySQL 切换到另一个数据库产品怎么办?我们将不得不修改我们调用DatabaseConnection 对象的每个地方,并将其替换为我们的新实现。或者,我们可以修改类本身——但我们仍然想在其他项目中使用原来的类,所以我们最终得到两个同名的实现,这只是自找麻烦,真的。
那么单元测试呢?当然,我们这样做是因为我们是优秀的开发人员!但是如果我们对使用数据库的函数进行单元测试,我们不希望测试实际上依赖于数据库,甚至不希望改变那里的东西。无法用模拟对象(仅返回静态数据)替换 DatabaseConnection,因为我们的项目与它紧密耦合。
这就是依赖注入的作用:它有助于防止紧密耦合。如果我们用$someObject->setDatabaseConnection($databaseConnection) 注入连接,我们可以在那里注入任何行为与原始对象相似的对象。我们可以注入模拟对象、替代实现或继承原始类的扩展。
现在依赖注入容器只是一个很好的帮手,可以更轻松地管理对象实例及其依赖关系,但在进行依赖注入时不需要它。