2012-01-28 53 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