为什么在PHP框架中使用依赖注入组件


Why to use Dependency Injection components in PHP frameworks

当我第一次看到依赖注入组件,如PHP-DI、Symfony2DI等时,我认为有一种方法可以通过一个实例化将任何类的实例自动注入到任何类。

所以1.在根类中创建实例,如$foo = new Foo()2.然后我可以在任何对象中使用这个实例(比如全局单例),而无需传递对要从中调用的类的构造函数或方法的引用。

但我发现,基本上我可以通过两种方式使用依赖注入1.将实例的引用传递给构造函数2.创建所有对象所在的容器。此容器可以注入到其他类中,但"不建议这样做"。

由于这两种方法都可以在纯PHP中轻松完成,第一种方法很清楚,第二种方法可以用静态属性来解决,那么为什么要使用PHP-DI或Symfony2来完成这项工作呢?

为什么要在Singleton模式上使用依赖注入?

假设我们有一个名为DatabaseConnection的Singleton对象,它为我们封装了到MySQL数据库的连接,并做了一些其他巧妙的事情,谁知道呢。因为重用代码是一件好事,所以我们在很多项目中都使用了这个对象。

如果在某个时候我们决定将我们的一个项目从MySQL切换到另一个数据库产品,该怎么办?我们必须修改调用DatabaseConnection对象的每个地方,并用新的实现替换它。或者,我们可以修改类本身——但我们仍然想将原始类与其他项目一起使用,所以我们最终得到了两个同名的实现,这真的只是在找麻烦。

那么单元测试呢?当然,我们这样做是因为我们是优秀的开发人员!但是,如果我们对使用数据库的函数进行单元测试,我们不希望测试实际上依赖于数据库,甚至不希望更改数据库中的内容。没有办法用mock对象(只返回静态数据)替换DatabaseConnection,因为我们的项目与它紧密耦合

这就是依赖注入的作用:它有助于防止紧密耦合。如果我们用$someObject->setDatabaseConnection($databaseConnection)注入连接,我们可以在那里注入任何行为与原始对象相似的对象。我们可以注入mock对象、替代实现或继承原始类的扩展。

现在,依赖注入容器只是一个很好的助手,可以更容易地管理对象实例及其依赖关系,但进行依赖注入并不需要它。