2017-03-08 17 views
2

この例では、私は便器のコンテナで使用しているclassAclassBを持っています。PHP円の依存性に無限ループを引き起こすような陥凹のDICを防ぐ方法

これらはお互いに依存しています。しかし、これをシックプDICで設定すると、以下のコードは無限ループを引き起こします。

シンプルでこれを行う方法が必要ですが、私はそれをドキュメントで見ることはできません。無限ループを防ぐ?

+1

'にきびDIC'は本当ですか? – RiggsFolly

+0

母、http://pimple.sensiolabs.org/ – jon

+0

これはすべて同じファイルですか?そのファイルに散在している "使用"はそれをはっきりさせません。 – yivi

答えて

-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['ClassA']); 
}; 
// 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のインスタンスを開始/取得できます。

1

厳密に言えば、あなたの問題は実際には、にきび関連ではありません。

あなたは単純に循環的なコンストラクタ依存性を持っていますが、それらを修正する方法はありません。ニーズBニーズAニーズB ...

実際には、お互いに依存する2つのクラスはあまり意味がありません。しかし、では稀なのケースでは、2つのうちの1つが、インスタンス化後にのようなセッターまたはいくつかのメカニズムを使用してオブジェクトを注入するより軽い依存関係である必要があります。

コンテナを渡してClassBの内部をインスタンス化することで、依存関係を隠すことになります。この依存関係は、依存性注入コンテナを持つ目的よりも優れています。今すぐClassBContainerに依存していますが、最初は欲しかったのはClassAではありません。

代わりに、方法setA(Class A $a)ClassBに追加してください。

次に、DIコンテナではなく、実際に必要なときに$b->setA($container['ClassA']);を呼び出して依存関係を注入します。 Adam points outとして、サービスを拡張してサービス定義の設定ツールを使用して、コンテナにセッター注入を行うことさえできます。

もう一度言い換えると、あなたの主な問題は循環依存性を持つことです。それを再考してください。 非常にあなたの設計がいくつかの改良を加えた可能性が高い兆候です。

+0

シンプルな問題ではないかもしれませんが、シンプルで解決できます。私の答えを見てください。私はあなたと私の組み合わせが役に立つと思うので、私は私の考えであなたのものを参照します。 –

+0

@Adam、ええと、私はサービス定義の中でセッターを呼び出すことを提案しようとしていましたが、彼の主な問題は円形のデパートを持っていると考えています。 IMO(ずっと)より頻繁に、それは他の何かがデザインと間違っているというサインです。それでも、私はあなたの答えが好きです。 :) – yivi

+0

はい。私は私の答えでもこれを強調しました。良いチームワーク! –

2

@yiviは、最初に循環参照の有効性について有効な観察in their answerを作成します。だから私は本当にここであなたのデザインを評価すべきだと思っています。根本的な問題ではなく、症状を治療している可能性があります。ジェネリックサンプルコード(これは当面の問題のコードです)では、これについてコメントすることは不可能です。あなたはそれが価値があると思うなら、おそらくあなたのデザインについての新しい質問を提起するでしょうか?ここまたはCode Reviewの多分?

あなたがClassAClassBのデザインを管理している場合、このようなことに対する所定のアプローチは、コンストラクタインジェクションではなくセッタインジェクションを使用することです。

これは動作するはずです:

// 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です。

+0

@ YiviとAdam Cameronのお返事ありがとうございます。 あなたは、この循環的なコンストラクタの依存関係の問題が、より悪い設計に至る可能性があるという事実を暗示しています。私が持っているシナリオは、 - 私は、クエリクラスと検証クラスがあります。 Queryクラスには、検証クラスを通じてデータの検証が必要な多くのメソッドがあります。 検証メソッドの1つに、クエリクラス内のメソッドが必要です。 したがって、あなたのソリューションの1つを使用してコードに取り組むと、コードを構造化するためのより良い方法がありますか? あなたの返信にもう一度感謝します。私は示唆したように: – jon

+0

@jon別の質問を提起する、私は思う。このビットは実際には* this *の質問には関係しません。さらに、それはあなたにより多くの空間を与えるでしょう。また、一般的なオブジェクト指向設計の問題として、Pimple、DI、さらにはPHPからコンテキストを広げることができます。実際のメソッド名と用途を含むスタブクラスを実装することをお勧めします。この場合の名前と使用法は、意思決定を行う上で重要です。あなたのデザインが正しいかもしれません、btw。それは伝えにくいです。 –

関連する問題