2011-12-10 2 views
12

개체 배열을 만들고 있습니다. 주어진 객체의 한 번만 인스턴스를 포함하도록이 배열이 필요합니다. 동일한 객체에 대한 여러 참조가 예외를 throw해야합니다. 나는 이것을 달성하기 위해 다음 코드를 사용하고 있습니다 :순환 참조가있는 객체의 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

답은 매우 특별합니다. 기본적으로 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