我正在编写一些可重用的库,其中包含很少的类。 其中一个需要依赖,因为一些更复杂的逻辑,我想将该类的责任委托给其他地方(另一个类)。
我不想创建一个包,例如Symfony Bundle可以处理我的依赖注入,并提供一种将其与客户端代码集成的简单方法。 我的目标是提供可重用且独立于框架的解决方案。
我正在使用composer,而且我已经阅读过像php-di这样的DI容器。 php-di有一个demo应用程序示例,但它不符合我的要求。
库代码片段
<?php
class W3CAnalyzer implements WebStandardAnalyzer
{
private $httpClient;
public function __construct(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
public function analyze(string $url): WC3AnalysisMetaData
{
$siteContent = $this->httpClient->getContent($url);
//further logic there
}
}
正如您所看到的,W3CAnalyzer
包含依赖项HttpClient
类。
我会以某种方式配置一个DI容器来注册并解决该依赖关系。
示例客户端代码
<?php
class WebStandardController
{
private $webStandardAnalyzer;
public function __construct(WebStandardAnalyzer $webStandardAnalyzer)
{
$this->webStandardAnalyzer = $webStandardAnalyzer;
}
}
在客户端项目中,程序员将使用他的DI配置注册W3CAnalyzer
作为WebStandardAnalyzer
注入控制器(它并不重要)。
如果我在内部使用我的库中的一些DI配置和容器,我如何将此配置与客户端代码集成,那么是否有可能注册库类并且其所有依赖关系都已解决了? 我还不知道,我将如何在我的库中组织DI(这实际上是问题的第一部分),我想以某种方式使用上面提到的php-di库。
总结一下,如何在非框架可重用库中组织DI,以便可以在每个其他项目中使用该库(无论使用哪个框架),并且其(该库)依赖项也将在运行时期间解析项目
谢谢!
答案 0 :(得分:1)
class W3CAnalyzerFactory
{
public function build()
{
$Subject = new W3CAnalyzer(new HttpClient);
return $Subject
}
}
以上是我如何利用工厂模式,并取得了巨大的成功。如果new HttpClient
不足以满足您的代码(也就是说,它也需要构建),请执行以下操作:
class HttpClientFactory
{
public function build()
{
//modify this to actually construct the HttpClient object, with
//constructor and/or setter injections
$Subject = new HttpClient();
return $Subject
}
}
然后,您的W3CAnalyzerFactory
将如下所示:
class W3CAnalyzerFactory
{
public function build()
{
$Subject = new W3CAnalyzer(
(new HttpClientFactory)
->build()
);
return $Subject
}
}
然后,使用您的图书馆的人可以执行以下操作:
$WebStandardController = new WebStandardController(
(new W3CAnalyzerFactory())
->build()
);
或者,他们想要使用自己的DI设置。正如你所说,注入它并不重要,只是他们可以使用W3CAnalyzerFactory
类,然后一切就绪了。
提示:对于我的库和/或应用程序中的所有对象,我总是创建一个工厂类,即使没有注入任何内容。起初感觉罗嗦,但有一些好处。
HttpClient
)以便现在需要注入一些东西,那么使用HttpClientFactory
的所有内容都已经完成,你不需要去通过new HttpClient()
替换所有(new HttpClientFactory)->build()
行。new HttpClient
或(new HttpClientFactory)->build()
?请不要考虑它,只需使用工厂。)在我创建实现时创建这些工厂是我推荐的,因为它让它不受影响,并且不要求你稍后再回来并试着想出如何将事物串在一起。
我认为这种方法对于依赖注入来说是最简单的,当你不想或不能使用容器来帮助你时。
旁注:我将对象分配给$Subject
,然后return $Subject
分隔一行而不是仅仅执行return new Whatever...
的原因是因为我倾向于选择setter注入,这意味着我需要在构造之后对对象做事。尽管如此,您可以做最适合您的库和/或应用程序的方法。选择单词&#34; subject&#34;因为变量名称来自于我的单元测试$SUT
中调用我的对象的&#34;主题测试&#34;。这些都没有经过测试,所以我只是称它们$Subject
有一个很好的一致名称,可以帮助我轻松查看正在构建的对象。我的习惯再次完全是可选的。