2

在这个例子中,我有classA并且classB我正在使用疙瘩容器。

他们都相互依赖。但是,当使用 pimple DIC 进行设置时,以下代码会导致无限循环...

必须有一种方法可以在疙瘩中做到这一点,但我在文档中看不到它......任何想法如何防止无限循环?

// PIMPLE CONTAINER
use Pimple\Container;
$container = new Container();

use Classes\ClassA;
$container['ClassA'] = function ($c) {
  return new ClassA($c['ClassB']);
};

use Classes\ClassB;
$container['ClassB'] = function ($c) {
  return new ClassB($c['ClassA']);
};
4

3 回答 3

1

严格来说,你的问题与青春痘无关。

你只是有一个循环构造函数依赖,没有办法修复这些。A需要B需要A需要B...

问题是,通常,两个相互依赖的类没有多大意义。但在极少数情况下确实发生这种情况,两者之一应该是较轻的依赖项,您可以在实例化之后通过 setter 或类似的机制注入对象。

通过传递容器并在内部实例化ClassB,您隐藏了您的依赖项,这超出了拥有依赖项注入容器的目的。现在ClassB取决于Container,而不是ClassA,这是您首先想要的。

而不是这样做,只需将一个方法添加setA(Class A $a)到您的ClassB.

然后,通过在实际需要时调用$b->setA($container['ClassA']);而不是在 DI 容器上调用来注入依赖项。正如 Adam指出的那样,您甚至可以通过扩展服务并在服务定义中使用 setter 来在容器中进行 setter 注入。

但再次重申,您的主要问题是具有循环依赖。再想想。这可能表明您的设计可以进行一些改进。

于 2017-03-08T07:11:11.353 回答
1

@yivi 首先在他们的回答中对循环引用的有效性做出了有效的观察。所以我真的认为你应该在这里评估你的设计。您可能正在治疗症状,而不是根本问题。尽管给出了您的通用示例代码(也就是说,这是解决手头问题的好代码),但我们不可能对此发表评论。如果您认为值得一试,也许可以对您的设计提出一个新问题?也许在这里或在Code Review上?

如果您控制 and 的设计ClassAClassB那么对这类事情的规定方法是使用 setter 注入,而不是构造函数注入。

这应该有效:

// PIMPLE CONTAINER
use Pimple\Container;
$container = new Container();

use Classes\ClassA;
$container['ClassA'] = function ($c) {
  return new ClassA();
};

use Classes\ClassB;
$container['ClassB'] = function ($c) {
  return new ClassB();
};


$container->extend('ClassA', function ($instanceOfA, $container) {
    $instanceOfA->setB($container['ClassB']);

    return $instanceOfA;
});

$container->extend('ClassB', function ($instanceOfB, $container) {
    $instanceOfB->setA($container['ClassA']);

    return $instanceOfB;
});

(未经测试,可能包含拼写错误,但这是一般要点)

请注意原始构造函数如何不再使用依赖项,将其插入留给特定的设置器。这允许您在容器中创建服务,然后使用extend来调用相关的设置器以在此之后插入依赖项。

这在文档中:Modifying Services after Definition

于 2017-03-08T07:13:04.233 回答
-1
// PIMPLE CONTAINER
use Pimple\Container;
$container = new Container();

use Classes\ClassA;
$container['ClassA'] = function ($c) {
  return new ClassA($c['ClassB']);
};

use Classes\ClassB;
$container['ClassB'] = function ($c) {
  return new ClassB($c);
};

不是从 classB 实例化 ClassA,而是将容器传递给 ClassB。然后当您需要 ClassB 中的 ClassA 时,您可以使用您传递给它的容器来启动/获取 ClassA 的实例。

于 2017-03-08T04:23:06.720 回答