PHP依赖注入 - 注入容器(DIC)与否?

时间:2018-04-04 08:20:37

标签: php dependency-injection

考虑以下类结构:

enter image description here

框架代码(蓝色区域)

  • LOG类 - 简单的日志记录类。
  • DATABASE类 - 获取注入的LOG类。 (比如说,记录错误或SQL查询)。
  • REDIS类 - 也会注入LOG玻璃。
  • 业务逻辑类 - 获取上述所有构造函数。

应用程序代码:(黄色区域):

  • 实例化并使用框架代码。

当前框架构造函数代码类似于:

class Database{
    public function __constuctor (Logger $log, $databaseHost, $databaseUser, $databasePass, $databaseName){...}
}
class Redis{
    public function __constuctor (Logger $log, $redisHost, $redisUser, $redisPass){...}
}
class ACME{
    public function __constuctor (Database $db, Redis $redis, $otherStuff, ...){...}
}

在应用程序中,我们执行以下操作:

 $logger = new Logger();
 $db     = new Database($logger, 'db_host','db_user','db_user','db_pass');
 $redis  = new Redis($logger, 'redis_host','redis_user','redis_pass');

 $acme   = new Acme($db,$redis, ...other_stuf...);

构造函数变得非常冗长和丑陋,我很想创建一个依赖容器(DI)并将其作为单个构造函数参数传递。

考虑原则:" 对象不应该知道包含它的依赖容器",我觉得不行,因为这只会取代当前具有新依赖项的多个依赖项 - 依赖项容器(DIC)本身。

我感觉很好,我可以在应用程序部分(图像的黄色部分)中使用DIC注入,但是不能将DIC注入基础框架代码(蓝色部分)。

我错了吗?

注入DIC可以吗?

在这里使用服务定位器模式是不是更好?

1 个答案:

答案 0 :(得分:1)

  

在应用程序中,我们执行以下操作:

 $logger = new Logger();
 $db     = new Database($logger, 'db_host','db_user','db_user','db_pass');
 $redis  = new Redis($logger, 'redis_host','redis_user','redis_pass');

 $acme   = new Acme($db,$redis, ...other_stuf...);

这有时被称为穷人的依赖性注射

你想要的东西(我猜)应该是这样的:

$coolContainer = new SomeCoolDependencyInjectionContainer();
// ... do some configuration on the container
$app = $coolContainer->get('app'); // or whatever its usage interface is
$app->run(); // or any other way to launch the app

容器知道如何构建应用程序及其所有组件(知识来自为容器提供的配置或它的自动装配功能)。请注意,实例化在应用程序之外发生。应用程序应该已经构建了所有内容。

所以底线是:如果你正在使用一些DI容器,请确保它知道每个需要一个组件的记录器(实际上你可能想为应用程序的不同部分做特定的记录器)。 / p>

您可能会发现以下链接很有趣(当然,如果还没有阅读):

https://martinfowler.com/articles/injection.html

http://blog.ploeh.dk/2011/07/28/CompositionRoot/

依赖性更新:

通常在决定依赖数量时,请记住:

  • Uncle Bob's规则不超过3 我亲自传播给构造函数的函数/方法的参数
  • 单一责任原则
  • 正确考虑正确的代码结构

在我的实践中,它出现了,即使这些想法有点普遍,并且通用跟随它们使我的代码更清洁。清洁 - 一方面更具可读性和可理解性,另一方面更易于维护,更重要的是,因为它可以更快地执行重构或重新设计,而且工作量更少。所以基本上我认为这里的最佳实践不是特定于问题,而是反映了更高层次的普遍性。

尽管如此,关于一个班级的最终依赖数量,我不会遵循3的规则,无论什么"基础。偶尔我甚至可以有四个。通常,如果辅助类内部没有真正的逻辑,就会发生这种情况。嗯,它肯定有逻辑,但不是 那种逻辑。所以一般来说,如果我认为它不值得努力,我会让它留下来,直到出现一些真正的问题或者只是永远。