我试图在PHP中破解我自己的依赖注入容器,基于构造函数注入。容器实例化复杂对象,并根据构造函数中使用反射的类型提示为所需对象注入它们。
我明显偶然发现的一件事是,我可以注册多个可以注入的组件,它们具有相同的类型(扩展相同的类/实现相同的接口)。例如,如果两个对象都需要同时实现Iterator接口的不同对象,该怎么办? DI容器通常如何处理这个问题?你如何让容器决定哪些具有模糊接口的对象需要注入哪些复杂对象?
或者只有一个DI容器才能负责创建一种类型的复杂对象?换句话说:对于每个复杂对象,实例化一个不同的DI容器。我很难想象这是意图,对吗?
答案 0 :(得分:1)
你所描述的不是DI本身,而是自动装配,比普通DI更进一步。通常使用DI,您可以明确地将哪些组件连接到哪些组件。
自动装配DI仅适用于粗粒度组件,其中只有一种合理的给定类型实现(例如DAO)。如果类型不明确,那么您要么将其中一个标记为“主要”,要么将其他标记为“非候选”,或者使用所需组件的名称明确标记该依赖项。
答案 1 :(得分:1)
根据您的问题的含义,这是Guice(Java的DI框架)使用的内容:
如果您每次收到Foo
的注入请求时只想要一个不同的对象,那么在连接您的应用程序时,不要将Foo.class
绑定到Foo
的特定实例,而是绑定Provider<Foo>
,这是一个按需创建Foo
的对象。然后,注入Foo
的每个位置都将获得一个新实例。如果只是将Foo
绑定到类而不是Foo
实例(例如,Foo
是一个接口,并将它绑定到RealFoo.class
,这是一个实现{ {1}}),您也可以获得相同的效果 - 每次都会创建一个新实例。 (这是默认的“无范围”行为.Guice范围的行为超出了本评论的范围)
但是,如果您需要在连接应用程序时构建两个Foo
实例,然后能够说“在创建Foo
或{时使用此Foo实例” {1}},而在制作Bar
时会使用另一个实例,您所做的是注释注入点,然后在为应用程序连线时说出如下内容:
Baz
我假设您已经使用以下内容注释Bumble
的构造函数的参数:
Foo foo1 = new Foo("1");
Foo foo2 = new Foo("2");
bind(Foo.class).annotatedWith(Names.named("Bar")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Baz")).toInstance(foo1);
bind(Foo.class).annotatedWith(Names.named("Bumble")).toInstance(foo2);
同样适用于Bar
和public Bar(@Named("Bar") Foo foo) { ...
。当然,如果您使用相同的内容注释Baz
和Bumble
的构造函数,则可以跳过其中一个Bar
行。
我知道有基于反射的PHP注释处理框架,或者你可以使用基于参数名称的约定。