DI无法进行延迟加载?

时间:2016-10-30 11:38:01

标签: php class dependency-injection lazy-loading

依赖注入是否会导致延迟加载依赖性?

因为您需要将实例传递给构造函数,所以以后不能生成实例

2 个答案:

答案 0 :(得分:3)

  

依赖注入是否会导致延迟加载依赖性?

不,它不会使延迟加载变得不可能。我甚至会争论相反,我甚至会说动态语言(如PHP和Ruby)比静态类型语言(如Java和C#)更容易。

由于您的组件编程为抽象,因此很容易为同一个合同注入一个实现,该实现包含可以延迟加载的实际实现。包装器就像一个代理,这使得消费者不会忘记任何延迟加载甚至正在进行的事实。这增加了可维护性。

我的PHP非常生疏,所以下一个例子可能不是'编译'(任何PHP开发,请随时更新这个例子),但以下显示了这个想法。

这里我们看到一些实现一些业务逻辑的类(ShipOrderHandler),它依赖于记录器依赖:

class ShipOrderHandler {
    private $logger;

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

    function Handle($command) {
        $this->logger->Log("shipping order " + $command->OrderId);
    }
}

class DatabaseLogger {

    function Log($message) {
        // log the message
    }
}

这是我们为ShipOrderHandler构建对象图的方法:

$handler = new ShipOrderHandler(new DatabaseLogger());

不要想象我们的DatabaseLogger实际上很难初始化。利用DI和动态语言的强大功能,我们可以简单地为记录器摘要添加代理实现;我们称之为LazyLogger。我们的新LazyLogger可能如下所示:

class LazyLogger {
    private $loggerFactory;
    private $logger;
    function __construct($loggerFactory) {
        $this->loggerFactory = $loggerFactory;
    }

    function Log($message) {
        if (!$this->logger) $logger = $loggerFactory();
        $this->logger.Log($message);
    }
}

我们现在可以将此LazyLogger应用于我们的Composition Root,以便懒惰地创建DatabaseLogger,而不对我们的应用程序组件进行任何更改:

$handler = new ShipOrderHandler(
    new LazyLogger(function() { return new DatabaseLogger() });

这里我们将DatabaseLogger的创建包装在一个注入LazyLogger的匿名函数中。当第一次调用LazyLogger的{​​{1}}方法时,将调用工厂方法,创建Log并且DatabaseLogger将缓存该实例并将使用它直到它超出范围本身。

正如您所看到的,依赖注入实际上并不限制延迟加载的使用;相反:它允许延迟加载而无需在整个应用程序中进行彻底的更改。

这是DI的力量。

答案 1 :(得分:0)

你会在http://php.budgegeria.de/flzsbalQV2中找到一个使用延迟加载的Symfony DI组件示例。

类Bar依赖于Foo,它被配置为服务。当Foo实例化时,将运行回声。如您所见,当第一次访问Foo依赖项方法时,将创建实例。

您需要ocramius / proxy-manager编写器包。也可以将这种惰性行为实现到其他DI容器中。