我刚刚在我的宠物项目dump_r()中重新设计了递归检测算法
https://github.com/leeoniya/dump_r.php
检测对象递归并不太困难——您可以使用splobjecthash()来获取对象实例的唯一内部id,将其存储在dict中,并在转储其他节点时与之进行比较。
对于数组递归检测,我有点困惑,我没有发现任何有用的东西。php本身能够识别递归,尽管它似乎做得太晚了一个周期编辑:nvm,它发生在需要的地方:)
$arr = array();
$arr[] = array(&$arr);
print_r($arr);
它是否必须跟踪递归堆栈中的所有内容,并与其他数组元素进行浅层比较?
如有任何帮助,我们将不胜感激,
谢谢
由于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']);
}
你可以把这个函数包装成另一个接受值而不是引用的函数,但你会从第二级收到RECURSION通知。我认为print_r也可以这样做。
如果我错了,有人会纠正我,但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;
}