我正在编写一些可重用的库,其中包含几个类。 其中一个需要有依赖关系,因为一些更复杂的逻辑,我想将该类的责任委托(delegate)给其他地方(另一个类)。
我不想创建一个包,例如Symfony Bundle 可以处理我的依赖注入(inject)并提供一种将其与客户端代码集成的简单方法。 我的目标是提供可重用且独立于框架的解决方案。
我正在使用 composer我读过有关 DI 容器的信息,例如 php-di . 有一个 demo php-di的应用示例,但它不符合我的要求。
库代码片段
<?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 注入(inject)到 Controller 中(这并不重要)。
如果我在我的库内部使用一些 DI 配置和容器,我如何将这个配置与客户端代码集成,这样就有可能注册库类并且它的所有依赖项都已经解决了? 我还不知道,我将如何在我的库中组织 DI(这实际上是问题的第一部分),我想以某种方式使用上面提到的 php-di 库。
总而言之,如何在非框架可重用库中组织 DI,以便该库可以在每个其他项目(无论使用哪个框架)中使用,并且它的(该库)依赖项也将在该项目的运行时得到解决项目。
谢谢!
最佳答案
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 设置。正如您所说,他们如何注入(inject)并不重要,重要的是他们可以使用 W3CAnalyzerFactory 类,然后一切就绪。
提示:对于我的库和/或应用程序中的所有对象,我总是创建一个工厂类,即使没有注入(inject)任何东西。一开始感觉很冗长,但有几个好处。
HttpClient),所以它现在确实需要注入(inject)一些东西,那么所有使用HttpClientFactory的东西都已经完成了,你不需要不需要遍历并将所有 new HttpClient() 行替换为 (new HttpClientFactory)->build()。new HttpClient 还是 (new HttpClientFactory)->build()?别想了,直接使用工厂。)我建议在创建实现时创建这些工厂,因为它可以解决问题,并且不需要您稍后再回来尝试考虑如何将事物串在一起。
我认为当您不想或不能使用容器来帮助您时,这种方法对于依赖注入(inject)是最简单的。
旁注:我将对象分配给 $Subject 然后 return $Subject 一个单独的行而不是仅仅做 return new Whatever... 是因为我倾向于更喜欢 setter 注入(inject),这意味着我需要在对象构造后对它做一些事情。不过,您可以做最适合您的图书馆和/或应用程序的事情。选择“subject”一词作为变量名是因为在我的单元测试 $SUT 中为“Subject Under Test”调用了我的对象。这些未在测试中,所以我只是将它们命名为 $Subject 以获得一个很好的一致名称,这有助于我轻松地了解正在构建的对象是什么。同样,我的这个习惯完全是可选的。
关于php - 在自己的可重用库中提供依赖注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45253798/
我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我今天看到了一个ruby代码片段。[1,2,3,4,5,6,7].inject(:+)=>28[1,2,3,4,5,6,7].inject(:*)=>5040这里的注入(inject)和之前看到的完全不一样,比如[1,2,3,4,5,6,7].inject{|sum,x|sum+x}请解释一下它是如何工作的? 最佳答案 没有魔法,符号(方法)只是可能的参数之一。这是来自文档:#enum.inject(initial,sym)=>obj#enum.inject(sym)=>obj#enum.inject(initial){|mem
有什么方法可以告诉sidekiq一项工作依赖于另一项工作,并且在后者完成之前无法开始? 最佳答案 仅使用Sidekiq;答案是否定的。正如DickieBoy所建议的那样,您应该能够在依赖作业完成时将其启动。像这样。#app/workers/hard_worker.rbclassHardWorkerincludeSidekiq::Workerdefperform()puts'Doinghardwork'LazyWorker.perform_async()endend#app/workers/lazy_worker.rbclassLaz
我经常将预配置的lambda插入可枚举的方法中,例如“map”、“select”等。但是“注入(inject)”的行为似乎有所不同。例如与mult4=lambda{|item|item*4}然后(5..10).map&mult4给我[20,24,28,32,36,40]但是,如果我制作一个2参数lambda用于像这样的注入(inject),multL=lambda{|product,n|product*n}我想说(5..10).inject(2)&multL因为“inject”有一个可选的单个初始值参数,但这给了我......irb(main):027:0>(5..10).inject
是否有self验证的问题列表。看着那个,我可以确定我知道。我应该复习一下。在学习的过程中,我列了一个这样的list,但它只包含我在某处听说过的项目。我需要一段时间才能找到新的东西。 最佳答案 以下是针对ruby和Rails的一些测试列表。证书名称:RubyonRails谁提供:oDeskIncorporation认证费用:免费网站:https://www.odesk.com/tests/985?pos=0证书名称:RubyonRails提供者:Techgig.com(TimesBusinessSolutionsLimited(T
为了在我的mac上为一个rails项目安装mysql,我遵循了安装Homebrew软件和删除mac端口的在线建议。这是问题开始的地方。rails项目不会构建,我得到这个:[rake--prereqs]rakeaborted!dlopen(/Users/Parker/.rvm/gems/ruby-1.9.3-p448/gems/nokogiri-1.6.0/lib/nokogiri/nokogiri.bundle,9):Librarynotloaded:/opt/local/lib/libiconv.2.dylibReferencedfrom:/Users/Parker/.rvm/gem
我正在学习Ruby,遇到了inject。我正处于理解它的风口浪尖,但当我是那种需要真实世界的例子来学习一些东西的人时。我遇到的最常见的例子是人们使用inject来添加一个(1..10)范围的总和,我不太关心这个。这是一个任意的例子。在实际程序中我会用它做什么?我正在学习,所以我可以继续使用Rails,但我不必有一个以Web为中心的示例。我只需要一些我可以全神贯注的目标。谢谢大家。 最佳答案 inject有时可以通过它的“其他”名称reduce更好地理解。它是一个对Enumerable进行操作(迭代一次)并返回单个值的函数。它有许多有
Ruby中防止SQL注入(inject)的好方法是什么? 最佳答案 直接使用ruby?使用准备好的语句:require'mysql'db=Mysql.new('localhost','user','password','database')statement=db.prepare"SELECT*FROMtableWHEREfield=?"statement.execute'value'statement.fetchstatement.close 关于ruby-防止SQL注入(inject
我有一个Rails2.3.5应用程序,其中包含我希望保护的API。没有用户-它是一个应用到应用风格的网络服务(更像是亚马逊服务而不是facebook),所以我想使用两条腿的OAuth方法来实现它。我一直在尝试使用oauth-plugin服务器实现作为开始:http://github.com/pelle/oauth-plugin...但它的构建需要三足(网络重定向流)oauth。在我深入研究对其进行更改以支持两条腿之前,我想看看是否有更简单的方法,或者是否有人有更好的方法让Rails应用程序实现成为两条腿的OAuth提供程序。 最佳答案