在PHP中检查数组是否递归的最佳方法是什么?
给出以下代码:
<?php
$myarray = array('test',123);
$myarray[] = &$myarray;
print_r($myarray);
?>
来自 PHP手册:
print_r()将显示 递推 当它到达第三个
数组的元素。
似乎没有任何其他方法可以扫描数组
递归引用,所以如果你需要检查它们,你必须这样做
使用print_r()及其第二个参数来捕获输出并查看
为了这个词 递推。
有更优雅的检查方式吗?
PS。这是我使用regex和print_r()检查并获取递归数组键的方法
$pattern = '/\n \[(\w+)\] => Array\s+\*RECURSION\*/';
preg_match_all($pattern, print_r($value, TRUE), $matches);
$recursiveKeys = array_unique($matches[1]);
谢谢
尝试解决“不可能”的问题总是很有趣!
这是一个函数,如果递归发生在顶层,它将检测递归数组:
function is_recursive(array &$array) {
static $uniqueObject;
if (!$uniqueObject) {
$uniqueObject = new stdClass;
}
foreach ($array as &$item) {
if (!is_array($item)) {
continue;
}
$item[] = $uniqueObject;
$isRecursive = end($array) === $uniqueObject;
array_pop($item);
if ($isRecursive) {
return true;
}
}
return false;
}
看到它在行动。
检测递归 任何 水平显然会更棘手,但我认为我们可以同意它似乎可行。
更新
这里是递归(双关语无意但令人愉快)的解决方案,可以检测任何级别的递归:
function is_recursive(array &$array, array &$alreadySeen = array()) {
static $uniqueObject;
if (!$uniqueObject) {
$uniqueObject = new stdClass;
}
$alreadySeen[] = &$array;
foreach ($array as &$item) {
if (!is_array($item)) {
continue;
}
$item[] = $uniqueObject;
$recursionDetected = false;
foreach ($alreadySeen as $candidate) {
if (end($candidate) === $uniqueObject) {
$recursionDetected = true;
break;
}
}
array_pop($item);
if ($recursionDetected || is_recursive($item, $alreadySeen)) {
return true;
}
}
return false;
}
看到它在行动。
当然,也可以通过手动保持堆栈来编写迭代而不是递归,这对于非常大的递归级别是个问题的情况会有所帮助。
我前段时间深入研究过,我无法找到任何有用的机制来检测PHP数组中的递归。
问题归结为是否可以判断两个PHP变量是否是对同一事物的引用。
如果您正在使用对象而不是数组(甚至是数组中的对象),那么就有可能,因为可以找出两个对象是否使用相同的引用 spl_object_hash()
。因此,如果结构中有对象,则可以通过遍历树并比较对象来检测递归。
但是对于常规变量 - 即非对象 - 使用标准PHP无法轻松检测到这一点。
工作是要使用 print_r()
(如你所知)或 var_dump()
,但这些都不是特别优雅的解决方案。
xDebug还提供了一个可以提供帮助的功能, xdebug_debug_zval()
,但这显然只有在你安装了xDebug时才可用,这在生产系统上是不推荐的。
进一步的意见和建议 在这里。
以下函数比接受答案中的代码更简单[看法],并且似乎适用于我能够设想的任何用例。它似乎也出乎意料地快,通常需要几微秒,尽管我没有做过广泛的基准测试。如果有问题,如果有人能说出来,我将不胜感激?
// returns TRUE iff the passed object or array contains
// a self-referencing object or array
function is_r($obj, &$visited=array())
{
$visited[] = $obj;
foreach ($obj as $el)
{
if (is_object($el) || is_array($el))
{
if (in_array($el, $visited, TRUE))
return TRUE;
if (is_r($el, $visited))
return TRUE;
}
}
return FALSE;
}
我相信你无法检查。阅读 参考文件 有关参考的更多信息。
这是检查RECURSION的函数(来自PHP文档注释),尽管看起来很慢(我不建议):
function is_array_reference ($arr, $key) {
$isRef = false;
ob_start();
var_dump($arr);
if (strpos(preg_replace("/[ \n\r]*/i", "", preg_replace("/( ){4,}.*(\n\r)*/i", "", ob_get_contents())), "[" . $key . "]=>&") !== false)
$isRef = true;
ob_end_clean();
return $isRef;
}