【问题标题】:PHP Dependency Injection - to inject Container (DIC) or not?PHP 依赖注入 - 是否注入容器(DIC)?
【发布时间】:2018-09-13 17:21:39
【问题描述】:

考虑以下类结构:

框架代码(蓝色区域)

  • 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) 本身。

感觉不错的是可以在Application部分使用DIC的注入(图中黄色部分),但是在基础框架代码(蓝色部分)中注入DIC就不行了。

我错了吗?

注入DIC可以吗?

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

【问题讨论】:

  • 你试过用谷歌搜索那个主题吗?你不是第一个问这个问题的人
  • 是的,尝试了很多。也在这里,在 SO 中。在这种情况下,我发现的建议是:1)将应用程序拆分为更小的部分,以减少构造函数参数长度和依赖关系(不适合我)。 2)使用服务定位器或单例(静态方法) - 由于某种原因也被认为是一种不好的做法。其实大家都推荐使用DI,但是没有人给出一个最佳实践如何DI纠正和处理大量需要注入的引用
  • “大量引用”是什么意思?可能您有一些几乎不违反 SRP 的类,需要拆分成更小、更易于维护且依赖项更少的类?

标签: php dependency-injection


【解决方案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 容器,请确保它知道为每个需要使用的组件使用什么记录器(实际上您可能想要为应用程序的不同部分创建特定的记录器)。

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

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

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

依赖项更新:

通常在决定依赖数量时我会牢记:

  • Uncle Bob's 规则不超过 3 我个人传播给构造函数的函数/方法的参数
  • 单一责任原则
  • 正确代码结构的一般注意事项

根据我的实践,尽管这些想法有些笼统和通用,但遵循它们会使我的代码更简洁。更清洁——一方面意味着更具可读性和可理解性,另一方面更易于维护,这更重要,因为它可以更快地执行重构或重新设计,而且工作量更少。所以基本上我认为这里的最佳实践不是针对特定问题的,而是反映了更高层次的普遍性考虑。

不过,关于一个类提出的最终依赖项数量,我不遵循“无论如何”基础上的 3 规则。有时我什至可以有四个。如果它是一个辅助类,里面没有真正的逻辑,通常会发生这种情况。嗯,它肯定有逻辑,但不是那种的逻辑。所以一般来说,如果我发现它真的不值得付出努力,我会让它一直存在,直到出现一些真正的问题或永远存在。

【讨论】:

  • 是的,这就是我打算做的 - 使用 DI 容器作为合成根。对于“bean”(组件)构造函数优化 - 使它们更短的最佳实践是什么 - 一些构造函数接受超过 6-7 个参数,对于这些类,我嘴里的坏味道仍然存在......
猜你喜欢
  • 2014-09-15
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 1970-01-01
  • 2013-04-30
相关资源
最近更新 更多