2011-12-10 45 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

原來,答案非常簡單。看起來,默認情況下,in_array在測試針的草垛時進行非嚴格比較(相當於一個==操作)。這意味着它會檢查所有屬性是否相等,這意味着它開始遍歷對象圖,並且如果在該圖中有循環引用,則會導致麻煩。

in_array函數有一個嚴格的模式,但是,據我所知,這相當於一個===操作。這似乎導致它檢查引用以查看它們是否指向相同的對象而不是比較所有屬性。

只需改變代碼:

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

使得表現爲我想它沒有它觸發遞歸錯誤行爲的方法。

我不得不說,我有點驚訝,PHP默認情況下不會這樣做。另一方面,我想我真的不應該對PHP的弱類型再次引起我的問​​題感到驚訝。 :)

1

我只會使用SplObjectStoragespl_object_hash

你說得對,當php比較事物時,它遞歸地遍歷結構(也是數組)。

+0

沒有辦法只比較指針嗎? – mifki

+1

@mifki你可以輸入strict ===比較。它會比較物體的點數。 – NikiC

+0

感謝您的回覆,但我認爲我找到了解決方案。 – GordonM