3

我正在尝试基于构造函数注入在 PHP 中破解我自己的依赖注入容器。容器实例化复杂对象,并使用反射根据构造函数中的类型提示向它们注入所需的对象。

我显然偶然发现的一件事是我可以注册多个可以注入的相同类型的组件(扩展相同的类/实现相同的接口)。例如,如果两个对象都需要实现 Iterator 接口的不同对象怎么办。DI Containers 通常如何处理这个问题?如何让容器决定哪些接口不明确的对象需要注入到哪些复杂对象中?

还是单个 DI 容器只负责创建一种类型的复杂对象?换句话说:为每个复杂对象实例化一个不同的 DI 容器。我很难想象这是意图,对吧?

4

2 回答 2

1

您所描述的不是 DI 本身,而是自动装配,比普通 DI 更进一步。通常使用 DI,您可以明确配置哪些组件连接到哪些组件。

Autowired DI 仅适用于粗粒度组件,其中给定类型(例如 DAO)只有一个合理的实现。在类型不明确的情况下,您可以将其中一个标记为“主要”,或者将其他标记为“非候选”,或者使用您需要的组件的名称显式标记依赖项。

如果有帮助,您可以在此处此处阅读 Spring 如何处理自动装配

于 2009-09-07T23:23:14.557 回答
1

根据您的问题的意思,以下是 Guice(Java 的 DI 框架)使用的内容:

如果您只是在每次有注入请求时都想要一个不同的对象Foo,那么在连接您的应用程序时,不要绑定Foo.class到 的特定实例Foo,而是绑定 a Provider<Foo>,这是一个Foo按需创建的对象。然后,每一个Foo被注入的地方都会得到一个新的实例。如果您只是绑定Foo到一个类而不是Foo实例(例如,Foo是一个接口,并且您将它绑定到RealFoo.class一个实现的类Foo),您也会得到相同的效果 - 每次都会创建一个新实例。(这是默认的“无作用域”行为。Guice 作用域的行为超出了本评论的范围)

但是,如果您需要Foo在连接应用程序时构建两个实例,然后能够说“这个 Foo 的实例在制作 aBar或 a时使用Baz,而另一个实例在制作 a 时使用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) { ...

同样对于BazBumble。当然,如果你用相同的东西注解 和 的构造函数BarBaz你可以跳过其中的bind一行。

我知道有基于反射的 php 注释处理框架,或者您可以使用基于参数名称的约定。

于 2009-09-07T23:46:35.990 回答