2011-12-10 18 views
12

私はオブジェクトの配列を構築しています。この配列には、指定されたオブジェクトの一度のインスタンスのみを格納する必要があります。同じオブジェクトへの複数の参照が例外をスローする必要があります。私はこれを達成するために、次のコードを使用しています:循環参照を持つオブジェクトのin_array

public function addField ($name, iface\Node $field) 
{ 
    // Prevent the same field being added multiple times 
    if (!in_array ($field, $this -> fields)) 
    { 
     $this -> fields [$name] = $field; 
     $field -> setParent ($this); 
    } 
    else 
    { 
     throw new \InvalidArgumentException ('This field cannot be added to this group'); 
    } 
    return ($this); 
} 

は、これは私がNodeインタフェースを実装するオブジェクトを実装し始めたときに問題につながる始め、彼らは循環参照を含めることができるよう(彼らは彼らの子ノードのコレクションを保持します各子供はその親を参照している)。生成され、次のエラーが発生することができますフィールドを追加しようとすると:

PHP Fatal error: Nesting level too deep - recursive dependency?

私はPHPはオブジェクト全体の配列を横断しようとしているだけではなく、彼らは同じ値を保持するかどうかを確認するために、オブジェクト参照を比較している疑いがあるとしたがって、同じオブジェクトを指します。

私がin_arrayに行う必要があるのは、格納しているオブジェクト参照とフィールドのオブジェクト参照を比較するだけです。これにより、オブジェクトツリー全体を横断して再帰問題に陥るのを防ぐことができます。

これを行う方法はありますか?

+0

オブジェクトに「__equals」をオーバーライドして、より適切な等価性チェックの方法を実装してください。 –

答えて

16

答えは非常に単純です。デフォルトでは、針のhaystackをテストするとき、in_arrayは非厳密な比較(==演算に相当)を実行するように見えます。これは、すべてのプロパティが等しいことをチェックすることを意味します。つまり、オブジェクトグラフをトラバースすることを意味し、そのグラフに循環参照があると問題につながります。

しかし、in_array関数は厳密なモードを持っていますが、私の知る限り、===操作と同等です。これは、参照をチェックして、すべてのプロパティを比較するのではなく、同じオブジェクトをポイントしているかどうかを確認するように見えます。単純にコードを変更

if (!in_array ($field, $this -> fields, true)) 

は、私はそれはそれは再帰エラーをトリガすることなく動作するように望んでいた通りの方法で振る舞うことができます。

私は、PHPがデフォルトでこのモードを実行しないと少し驚いています。一方、私は、PHPの弱いタイピングが私にもう一度問題を引き起こしたことに本当に驚かされるべきではないと思います。 :)

1

SplObjectStorageまたはspl_object_hashのいずれかを使用します。

あなたが正しいです、phpが物を比較するとき、それは構造を再帰的に(配列も)横断します。

+0

ポインタだけを比較する方法はありませんか? – mifki

+1

@mifki strict ===比較を行うことができます。オブジェクトのポイントを比較します。 – NikiC

+0

応答をありがとう、しかし私は解決策を見つけたと思う。 – GordonM