[英]PHP How to prevent pimple DIC causing infinite loop on a circular dependency
在此示例中,我將classA
和classA
與classB
容器一起使用。
他們都相互依賴。 然而,當用 pimple DIC 設置它時,下面的代碼會導致無限循環......
必須有一種方法可以在 pimple 中做到這一點,但我在文檔中看不到它......任何想法如何防止無限循環?
// 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']);
};
嚴格來說,你的問題與青春痘無關。
你只是有一個循環構造函數依賴,沒有辦法修復它們。 A需要B需要A需要B...
問題是,通常,兩個相互依賴的類沒有多大意義。 但是在這種情況發生的極少數情況下,兩者之一應該是較輕的依賴項,您可以在實例化之后通過 setter 或類似機制注入對象。
通過傳遞容器並在ClassB
內部實例化,您隱藏了您的依賴項,這超出了擁有依賴項注入容器的目的。 現在ClassB
取決於Container
,而不是ClassA
,這是您首先想要的。
而不是這樣做,只需將方法setA(Class A $a)
到您的ClassB
。
然后,您通過調用$b->setA($container['ClassA']);
注入您的依賴項$b->setA($container['ClassA']);
當您真正需要它時,而不是在 DI 容器上。 正如 Adam指出的那樣,您甚至可以通過擴展您的服務並在服務定義上使用 setter 來在您的容器中進行 setter 注入。
但再次重申,您的主要問題是有一個循環依賴。 再想一想。 這很可能表明您的設計可以進行一些改進。
@yivi 首先在他們關於循環引用有效性的回答中做出了有效的觀察。 所以我真的認為你應該在這里評估你的設計。 您可能正在治療症狀,而不是根本問題。 盡管考慮到您的通用示例代碼(這是解決手頭問題的好代碼,說),但我們不可能對此發表評論。 如果您認為值得的話,也許可以對您的設計提出一個新問題? 在這里或在Code Review 上,也許?
如果您控制ClassA
和ClassB
的設計,那么處理此類事情的規定方法是使用 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;
});
(未經測試,可能包含拼寫錯誤,但這是一般要點)
請注意原始構造函數如何不再采用依賴項,將其插入留給特定的 setter。 這允許您在容器中創建服務,然后使用extend
然后調用相關的設置器在此之后插入依賴項。
這是在文檔中: Modifying Services after Definition 。
// 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 的實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.