构造函数注入

对象通常依赖于其他对象。应该将依赖项作为参数传递给构造函数,而不是在构造函数中创建依赖项。这确保了对象之间没有紧密耦合,并且能够改变对类实例化​​的依赖性。这有许多好处,包括通过使依赖项显式化使代码更容易阅读,以及使测试更简单,因为可以更容易地切换和模拟依赖项。

在以下示例中,Component 将取决于 Logger 的实例,但它不会创建一个。它需要将一个作为参数传递给构造函数。

interface Logger {
    public function log(string $message);
}

class Component {
    private $logger;

    public function __construct(Logger $logger) {
        $this->logger = $logger;
    }
}

没有依赖注入,代码可能看起来类似于:

class Component {
    private $logger;

    public function __construct() {
        $this->logger = new FooLogger();
    }
}

使用 new 在构造函数中创建新对象表示未使用依赖注入(或未使用不完整),并且代码紧密耦合。这也表明代码未经过严格测试,或者可能有严格的测试,对程序状态做出错误的假设。

在上面的示例中,我们使用依赖注入,如果需要,我们可以轻松地更改为不同的 Logger。例如,我们可能使用记录到不同位置的 Logger 实现,或使用不同日志记录格式的 Logger 实现,或者记录到数据库而不是文件的 Logger 实现。