web-dev-qa-db-ja.com

致命的なエラー:ネストレベルが深すぎます-再帰的な依存関係ですか?

ネストされたオブジェクトの複雑な階層があり、すべての子オブジェクト(親クラスにオブジェクトの配列が格納されています)には、親にリンクするプロパティが含まれています。かなり単純で簡単で、実際の問題はありません。階層内の任意のオブジェクトのvar_dumpを実行すると、期待どおりに、ダンプに再帰的な参照が表示されます。

FIRSTGEN 
   _children array of objects of type SECONDGEN
      SECONDGEN #1
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #1
               _parent object of type SECONDGEN
            THIRDGEN #2
               _parent object of type SECONDGEN
      SECONDGEN #2
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #3
               _parent object of type SECONDGEN

最近、その階層にいくつかの新しい要素を追加しましたが、それらはまったく同じパターンに従っていません。それらは最上位の親のオブジェクトの配列に格納されますが、親ではなく兄弟にそれらをリンクするプロパティが含まれています。ここでvar_dumpを実行すると、「致命的エラー:ネストレベルが深すぎます-再帰的な依存関係ですか?」というメッセージが表示されます。

FIRSTGEN 
   _children_1 array of objects of type SECONDGEN_1
      SECONDGEN_1 #1
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #1
               _parent object of type SECONDGEN_1
            THIRDGEN #2
               _parent object of type SECONDGEN_1
      SECONDGEN_1 #2
         _parent object of type FIRSTGEN
         _children array of objects of type THIRDGEN
            THIRDGEN #3
               _parent object of type SECONDGEN_1
   _children_2 array of objects of type SECONDGEN_2
      SECONDGEN_2 #1
         _parent object of type SECONDGEN_1

そのvar_dump()を除いて、コード内の他のすべてが正しく動作します。この質問をするときに例を提供できるように、問題を示すために簡単な例を作成してみました。しかし、短いテストでそれを複製することはできませんでした。私のより複雑なコード内でのみです。

解決策は関係をリファクタリングしてSECONDGEN_2オブジェクトの_children_2配列を適切なSECONDGEN_1親に保持し、親関係を「正しい」ものにすることです...私はすでにこれを開始しています。しかし、私はこのエラーに興味をそそられ、他の誰かがこのエラーに遭遇したのか(そして自分でどのように対処したのか)と思いました。

23
Mark Baker

PHP自己参照コードの制限で、print_rvar_dumpvar_exportで表示するか、またはin_array。基本的に、オブジェクトが循環的に参照されている場合、これらの関数が再帰を停止する場所を知る方法はありません。

このバグレポート によると これを再現する の最も簡単な方法は次のとおりです:

$outText = var_export( $GLOBALS, true );
print_r($outText) ;

他のバグレポート メンション それも、いくつかのテストケースで。これがvar_dumpでのみトリガーされる場合は、あまり心配する必要はありません。これがデバッグ目的である場合、xdebugに関するWrikkenの提案は間違いなく2番目です。

10

これは、_==_ではなく_===_を使用して再帰オブジェクトを比較する場合にも発生します。

実際のオブジェクトインスタンスを比較する必要がある場合は、厳密な比較演算子_===_を使用します。同じクラス。

簡単な説明:

_$object == $objectToCompareWith_を使用してオブジェクトを比較する場合、PHPは最初のオブジェクトのすべての属性と値を2番目のオブジェクトと比較しています。この比較は、比較されるオブジェクトのプロパティであるオブジェクトに対して再帰的です。

つまり、両方のオブジェクトがオブジェクトを値として持つ属性を共有する場合、PHPはこれらの属性オブジェクト間で同じ_==_比較を行います。これらの属性オブジェクトの再帰的(例:自己参照オブジェクト)は、ネストレベルが最大に達するまで比較も再帰的に繰り返されます。

Josh Stuartとmazatworkのコメントで述べたように、in_array()array_search()などの配列関数を使用する場合、それぞれの_$strict_パラメーターをtrue

Richard Lord: "ネストレベルが深すぎます–再帰的な依存関係ですか?"

PHPマニュアル: "オブジェクトの比較"

82
flu

時々(ただし、そのような委託に使用される有効な制限があるため、めったにありません)、これが起こり、コードが適切に動作する限り、var_dump(本番環境ではなくデバッグツール)では対応できません。ただし、それでも必要var_dumpを使用するには、xdebugを実行することを強くお勧めします。この場合、max-depthを設定できますvar_dumpには、文字列ダンプの最大長と子の最大数が表示されます。

3
Wrikken

私はあなたと同じエラーを受け取りましたが、まったく異なるシナリオでした。他の誰かが私と同じ方法でここに来た場合に備えて、私は答えを投稿しています。

オブジェクトの配列を使用してカスタムソート(usort)を試行している場合、これは私がしなければならなかったことです:

function cmp($a, $b) {
    if($a->num_estimates == $b->num_estimates) return 0;

    return($a->num_estimates < $b->num_estimates) ? -1 : 1;
}
$c = usort(Company::$companies, "cmp");

それは明らかになった $object->num_estimatesは、数値ではなくオブジェクトを返す場合がありました。常に数値が返されることを確認したら、エラーはなくなりました。

1
Jacksonkr

マジックメソッド __ toString を使用して、文字列へのカスタム変換を定義できます。オブジェクトに目を通し、__ toStringを実装するときに再帰を深く掘り下げすぎないようにしてください。忘れないで、誤ってvar_dump、var_export、print_rなどを呼び出してください。

__toStringメソッドを定義すると、次のようにうまく機能します。

echo $ yourObjectHere;

これはうまく機能する私の現在の解決策ですが、var_dump、var_export、print_rを呼び出さないことを忘れないように、何かを保護したいのですが。

0
Paul

多分これは誰かを助ける。

私にとっての解決策は、pcre.recursion_limit php.ini内。ただし、問題はおそらく自分のコード内にあるため、他の回答を読んだ場合は一時的な回避策になります。

0
pduersteler