<?php
function is_cyclic(array &$array)
{
$lastKey = array_key_last($array);
if ($lastKey === null) {
// Array is empty
return false;
}
static $marker;
if ($marker === null) {
$marker = new stdClass();
}
if ($array[$lastKey] === $marker) {
return true;
}
$array[] = $marker;
foreach ($array as &$item) {
if (is_array($item) && is_cyclic($item)) {
array_pop($array);
return true;
}
}
array_pop($array);
return false;
}
// Contains reference to itself
$v = [1, 2, 3];
$v[1] = &$v;
// Contains nested array with reference to $x
$x = [1, [2, 3]];
$x[1][1] = &$x;
// Contains nested array with reference to an ancestor
$y = [1, [2, [3, 4]]];
$y[1][1][1] = &$y[1];
// Nested array contains reference to itself
$z = [1, [2, 3]];
$z[1][1] = &$z[1];
// This array is not recursive
$p = [1, 2, [3, 4, [5, 6, 7]]];
foreach (['v', 'x', 'y', 'z', 'p'] as $var) {
$arr = &${$var};
echo "Array \$$var | Cyclic: ";
var_export(is_cyclic($arr));
echo "\n";
echo "----------------\n";
var_dump($arr);
echo "\n\n";
}
- Output for 8.0.0 - 8.0.30, 8.1.0 - 8.1.31, 8.2.0 - 8.2.26, 8.3.0 - 8.3.15, 8.4.1 - 8.4.2
- Array $v | Cyclic: true
----------------
array(3) {
[0]=>
int(1)
[1]=>
*RECURSION*
[2]=>
int(3)
}
Array $x | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
*RECURSION*
}
}
Array $y | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
&array(2) {
[0]=>
int(2)
[1]=>
array(2) {
[0]=>
int(3)
[1]=>
*RECURSION*
}
}
}
Array $z | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
&array(2) {
[0]=>
int(2)
[1]=>
*RECURSION*
}
}
Array $p | Cyclic: false
----------------
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
array(3) {
[0]=>
int(5)
[1]=>
int(6)
[2]=>
int(7)
}
}
}
- Output for 7.3.0 - 7.3.33, 7.4.0 - 7.4.33
- Array $v | Cyclic: true
----------------
array(3) {
[0]=>
int(1)
[1]=>
&array(3) {
[0]=>
int(1)
[1]=>
*RECURSION*
[2]=>
int(3)
}
[2]=>
int(3)
}
Array $x | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
array(2) {
[0]=>
int(2)
[1]=>
&array(2) {
[0]=>
int(1)
[1]=>
*RECURSION*
}
}
}
Array $y | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
&array(2) {
[0]=>
int(2)
[1]=>
array(2) {
[0]=>
int(3)
[1]=>
*RECURSION*
}
}
}
Array $z | Cyclic: true
----------------
array(2) {
[0]=>
int(1)
[1]=>
&array(2) {
[0]=>
int(2)
[1]=>
*RECURSION*
}
}
Array $p | Cyclic: false
----------------
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
array(3) {
[0]=>
int(5)
[1]=>
int(6)
[2]=>
int(7)
}
}
}
preferences:
87.09 ms | 411 KiB | 5 Q