2012-01-28 56 views
14

我剛剛重新設計我的遞歸檢測算法在我的寵物項目dump_r()在PHP中檢測無限數組遞歸?

https://github.com/leeoniya/dump_r.php

檢測對象遞歸併不太難 - 您使用spl_object_hash()來獲取對象實例的唯一內部ID ,將其存儲在一個字典中,並在轉儲其他節點時與其進行比較。

對於數組遞歸檢測,我有點困惑,我還沒有發現任何有用的東西。 php本身能夠識別遞歸,儘管它似乎只做了一個週期。 編輯:NVM,它發生在那裏需要:)

$arr = array(); 
$arr[] = array(&$arr); 
print_r($arr); 

它不得不求助於跟蹤所有的遞歸棧,並做比較淺對所有其他數組元素?

任何幫助,將不勝感激,
謝謝!

+0

lol - eeewwwww。 – leeoniya 2012-01-28 01:39:40

+1

不是你的quesiton的答案,但我已經看到了測試'print_r($ var,true)'的指示遞歸的字符串的解決方案。這是一樣討厭,因爲你可以得到,但工程...看到[這裏](http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/)一個體面的妥協。 – Basic 2012-01-28 01:42:20

+0

我已刪除/編輯我的評論,以包含一個示例的鏈接,但我同意,它很臭 – Basic 2012-01-28 01:43:23

回答

9

因爲PHP的呼叫按值的機制,我在這裏看到的唯一的解決辦法就是循環引用數組中,並在其中設置的任意值,該值後來檢查它是否存在,以找出是否你之前在那裏:

function iterate_array(&$arr){ 

    if(!is_array($arr)){ 
    print $arr; 
    return; 
    } 

    // if this key is present, it means you already walked this array 
    if(isset($arr['__been_here'])){ 
    print 'RECURSION'; 
    return; 
    } 

    $arr['__been_here'] = true; 

    foreach($arr as $key => &$value){ 

    // print your values here, or do your stuff 
    if($key !== '__been_here'){ 
     if(is_array($value)){ 
     iterate_array($value); 
     } 

     print $value; 
    } 
    } 

    // you need to unset it when done because you're working with a reference... 
    unset($arr['__been_here']); 

} 

你可以換這個功能到接受值,而不是引用另一個函數,但你會從第2層上得到遞歸通知。我認爲print_r也一樣。

+0

**這**是我希望的解決方案 - 簡單而超讚。 – leeoniya 2012-02-15 17:53:30

3

有人會糾正我,如果我錯了,但PHP實際上是在適當的時候檢測遞歸。您的分配只需創建附加週期。這個例子應該是:

$arr = array(); 
$arr = array(&$arr); 

這將導致在

array(1) { [0]=> &array(1) { [0]=> *RECURSION* } } 

正如預期的那樣。


那麼,我有點好奇自己如何檢測遞歸,我開始谷歌。我發現這篇文章http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/與此解決方案:

function hasRecursiveDependency($value) 
{ 
    //if PHP detects recursion in a $value, then a printed $value 
    //will contain at least one match for the pattern /\*RECURSION\*/ 
    $printed = print_r($value, true); 
    $recursionMetaUser = preg_match_all('@\*RECURSION\*@', $printed, $matches); 
    if ($recursionMetaUser == 0) 
    { 
     return false; 
    } 
    //if PHP detects recursion in a $value, then a serialized $value 
    //will contain matches for the pattern /\*RECURSION\*/ never because 
    //of metadata of the serialized $value, but only because of user data 
    $serialized = serialize($value); 
    $recursionUser = preg_match_all('@\*RECURSION\*@', $serialized, $matches); 
    //all the matches that are user data instead of metadata of the 
    //printed $value must be ignored 
    $result = $recursionMetaUser > $recursionUser; 
    return $result; 
} 
+0

你是對的。它不晚。但我仍然需要一種方法在本機函數外執行此操作。 – leeoniya 2012-01-28 01:31:10

+0

好吧,這個解決方案並不完全是我所希望的,因爲它對大型結構徵稅極大,並依賴於內部不可控制的深度print_r()或序列化,這是我開始項目開始的原因之一,呵呵,但http://www.phpsadness.com/ :( – leeoniya 2012-01-28 02:02:43