一般来说,出于如何考虑单元测试的“新”操作员中概述的原因,我会加入 DI 人群:
但依赖注入如此重要的原因在于,在单元测试中,您希望测试应用程序的一小部分。要求是您可以独立于整个系统构建应用程序的那个小子集。如果您将应用程序逻辑与图形构造(新操作符)混合使用,那么除了应用程序中的叶节点之外,任何东西都无法进行单元测试。
将您的代码分成创建者图和协作者图将有助于保持您的代码可维护和可测试。更好的是,针对接口编写代码,并且很容易将具体实现与其他实现交换。这使得更改代码变得简单,因为您不必费力地寻找硬编码的依赖项。
例如,假设你Bar
需要一个记录器,你会做
class Foo
{
private $logger;
public function __construct(LogInterface $logger)
{
$this->logger = $logger;
}
}
然后你传入任何实现它的具体实现LogInterface
,比如 Database Logger 或 StdOutLogger 或者可能包含这两者的 Composite Logger。另一个例子是数据库对象。您可以在引导程序中创建一次,然后将其传递给使用它的对象。
如有疑问,请使用依赖注入。
但是,您不必总是注入东西。这取决于对象(您的 Bar)是Injectable 还是 Newable。引用 Misko Hevery 的话:
Injectable 类可以在其构造函数中请求其他 Injectable。[…] Injectables 往往有接口,因为我们可能不得不用对测试友好的实现来替换它们。但是,Injectable 永远不能在其构造函数中请求非 Injectable (Newable)。这是因为 DI 框架不知道如何生成 Newable。[...] Newables 的一些示例是:电子邮件、MailMessage、用户、信用卡、歌曲。如果您保持这种区别,您的代码将易于测试和使用。如果您违反此规则,您的代码将难以测试。
简而言之,当你有一些不能被合理注入的东西时,因为它是基于用户提供的或运行时信息,你可以new
的。对于值对象和数据类型尤其如此:
class Foo
{
private $storage;
public function __construct()
{
$this->storage = new SplObjectStorage;
}
}
注入没有意义SplObjectStorage
。它只是一种数据类型。