PHP 二传手注射

示例

设置程序也可以注入依赖项。

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

class Component {
    private $logger;
    private $databaseConnection;

    public function __construct(DatabaseConnection $databaseConnection) {
        $this->databaseConnection = $databaseConnection;
    }

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

    public function core() {
        $this->logSave();    
        return $this->databaseConnection->save($this);
    }

    public function logSave() {
         if ($this->logger) {
            $this->logger->log('saving');
        }
    }
}

当类的核心功能不依赖于依赖项来工作时,这尤其有趣。

在这里,唯一需要的依赖关系就是DatabaseConnection它的构造函数。该Logger依赖性是可选的,因此并不需要成为构造的一部分,使类更容易使用。

请注意,使用setter注入时,最好扩展功能而不是替换它。设置依赖项时,没有任何东西可以确认依赖项在某个时候不会改变,这可能会导致意外结果。例如,FileLogger可以首先设置a ,然后再MailLogger设置a。这会破坏封装并使日志难以查找,因为我们正在替换依赖项。

为了防止这种情况,我们应该setter注入中添加一个依赖项,如下所示:

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

class Component {
    private $loggers = array();
    private $databaseConnection;

    public function __construct(DatabaseConnection $databaseConnection) {
        $this->databaseConnection = $databaseConnection;
    }

    public function addLogger(Logger $logger) {
        $this->loggers[] = $logger;
    }

    public function core() {
        $this->logSave();
        return $this->databaseConnection->save($this);
    }

    public function logSave() {
        foreach ($this->loggers as $logger) {
            $logger->log('saving');
        }
    }
}

这样,每当我们使用核心功能时,即使没有添加记录器依赖项,它也不会中断,并且即使可以添加另一个记录器,添加的记录器也将被使用。我们正在扩展功能,而不是取代它。