有没有办法在纯PHP中检测循环数组?

pos*_*ist 19 php arrays recursion identity circular-reference

我正在尝试在PHP中实现自己的序列化/ var_dump样式函数.如果存在圆形阵列(有)的可能性似乎是不可能的.

在最近的PHP版本中,var_dump似乎检测到循环数组:

php > $a = array();
php > $a[] = &$a;
php > var_dump($a);
array(1) {
  [0]=>
  &array(1) {
    [0]=>
    *RECURSION*
  }
}
Run Code Online (Sandbox Code Playgroud)

我如何在PHP中实现我自己的序列化类型的方法,可以类似地检测?我不能只是跟踪我访问过的数组,因为数组在PHP严格比较返回包含相同的元素,并比较圆形阵列导致致命错误,反正不同的阵列真.

php > $b = array(1,2);
php > $c = array(1,2);
php > var_dump($b === $c);
bool(true)
php > $a = array();
php > $a[] = &$a;
php > var_dump($a === $a);
PHP Fatal error:  Nesting level too deep - recursive dependency? in php shell code on line 1
Run Code Online (Sandbox Code Playgroud)

我找了一种方法来找到一个数组的唯一id(指针),但我找不到一个.spl_object_hash仅适用于对象,而不适用于数组.如果我将多个不同的数组转换为对象,它们都会获得相同的spl_object_hash值(为什么?).

编辑:

在每个数组上调用print_r,var_dump或serialize,然后使用某种机制来检测这些方法检测到的递归的存在是算法复杂性的噩梦,并且基本上会使任何使用太慢而不能在大型嵌套数组上实用.

接受的回答:

我接受了下面的答案,这是第一个建议暂时改变一个数组以查看它是否确实与另一个数组相同的答案.这回答了"我如何比较两个阵列的身份?" 递归检测是微不足道的.

lig*_*ter 6

下面的isRecursiveArray(array)方法检测循环/递归数组.它通过临时将包含已知对象引用的元素添加到数组末尾来跟踪已访问的数组.

如果您需要帮助编写序列化方法,请更新您的主题问题并在您的问题中提供示例序列化格式.

function removeLastElementIfSame(array & $array, $reference) {
    if(end($array) === $reference) {
        unset($array[key($array)]);
    }
}

function isRecursiveArrayIteration(array & $array, $reference) {
    $last_element   = end($array);
    if($reference === $last_element) {
        return true;
    }
    $array[]    = $reference;

    foreach($array as &$element) {
        if(is_array($element)) {
            if(isRecursiveArrayIteration($element, $reference)) {
                removeLastElementIfSame($array, $reference);
                return true;
            }
        }
    }

    removeLastElementIfSame($array, $reference);

    return false;
}

function isRecursiveArray(array $array) {
    $some_reference = new stdclass();
    return isRecursiveArrayIteration($array, $some_reference);
}



$array      = array('a','b','c');
var_dump(isRecursiveArray($array));
print_r($array);



$array      = array('a','b','c');
$array[]    = $array;
var_dump(isRecursiveArray($array));
print_r($array);



$array      = array('a','b','c');
$array[]    = &$array;
var_dump(isRecursiveArray($array));
print_r($array);



$array      = array('a','b','c');
$array[]    = &$array;
$array      = array($array);
var_dump(isRecursiveArray($array));
print_r($array);
Run Code Online (Sandbox Code Playgroud)

  • 我认为暂时改变数组可能是测试两个数组是否相同的唯一合理方法.这是建议这种方法的第一个答案,所以我会接受它. (2认同)