PHP - 如果自动加载,为什么要使用依赖注入


PHP - if autoloading, why would you use dependancy injection?

请原谅这个问题可能很幼稚,但是我真的很困惑。使用依赖注入来分离代码似乎是一种很好的做法,以便您的类加载其依赖项。请轻松想象以下 类 Foo 具有类 Bar 的依赖关系

namespace Classes;
class Foo{
    protected barInstance;
    public function __construct(Bar $barInstance){
        $this->barInstance=$barInstance;
    }
}

但是,如果您要自动加载类,那么以下内容肯定在不需要 DI 的情况下做完全相同的事情吗?

namespace Classes;
use Classes/Bar;
class Foo{
    protected barInstance;
    public function __construct(){
        $this->barInstance=new Bar;
    }
}

感谢任何响应者。

自动加载可确保在引用类时定义该类。 依赖关系注入使您可以灵活地选择使用的对象实例。

在您的示例中,假设您的 Bar 类管理数据库连接。假设您有时想要连接到不同的数据库。

public function __construct(){
    $this->barInstance = new Bar();
}

现在,您必须重构Foo类来处理更改,因为您已将其与Bar实例紧密耦合。

public function __construct(Bar $barInstance){
    $this->barInstance = $barInstance;
}

现在,在不更改Foo的情况下,我可以针对不同的情况实例化不同的Bar实例。 一个常用的有用示例是单元测试。

在这两种情况下,自动加载都确保Bar及其自己的所有依赖项都是在Foo之外定义的。

以数据库连接为例。

你有

public class foo {
    public function __construct(DbConnectionInterface $db) { ... }
}
public class foo2 { 
    public function __construct(DbConnectionInterface $db) { ... }
}
...

等等

在你的"服务容器"中,你有类似的东西

$db = new PdoDbConnection(); // which implements DbConnectionInterface
$service['foo'] = new foo($db);
$service['foo2'] = new foo2($db);

如果明天你想使用 pdo 以外的其他东西,那么你只需要建立一个实现接口的新连接,然后你可以在一个地方更改你的数据库连接

$db = new NotPdoDbConnection(); // which implements DbConnectionInterface
$service['foo'] = new foo($db);
$service['foo2'] = new foo2($db);

如果你没有使用 DI,那么你应该在使用此类的所有类中将新的 PdoConnection() 更改为新的 NotPdoConnection()。但是在这种情况下,自动加载对您没有多大帮助。正如lsklyut所说,他的回答是两个不同的概念。

这是一个"虚拟"案例,但您可以阅读一些有关 DI 的有趣文章

http://fabien.potencier.org/what-is-dependency-injection.htmlhttp://www.martinfowler.com/articles/injection.html

这是两个独立的概念。自动加载将允许您不必在脚本中包含文件,并允许您按概念分隔类。就依赖注入而言,如果 Bar 有额外的依赖关系,并且不能简单地通过使用 new Bar() 而是使用 new Bar($dep 1, $dep 2) 来实例化,那么你创建 Bar 的逻辑将被埋在 Foo 的构造函数中,以及任何其他需要 Bar 的类的构造函数中。通过在注入之前反转在其他地方创建 Bar 的依赖项,您可以减轻 Foo 的额外责任。

自动加载和依赖注入是不相关的概念。

自动加载器知道如何加载类。当像new Foo()这样的简单语句运行时,解释器需要知道Foo类的定义。如果它还不知道,那么它会调用自动加载器,直到类可用。自动加载器知道每个类的定义位置并包含正确的文件。

依赖注入容器知道如何构建各种类型的对象。它不知道(也不关心)类加载。它假定当它new Bar()运行时,类Bar已经定义(或者可以自动加载)。