- var_dump: documentation ( source)
- spl_object_hash: documentation ( source)
- debug_print_backtrace: documentation ( source)
<?php
class RecursionDetector {
private array $obj_ref_stack = [];
private array $arr_ref_stack = [];
public function detect(&$val): bool {
switch (gettype($val)) {
case 'object':
$hash = spl_object_hash($val);
var_dump($hash);
if (isset($this->obj_ref_stack[$hash])) {
debug_print_backtrace();
return true;
}
$this->obj_ref_stack[$hash] = true;
$copy = (array) $val;
break;
case 'array':
$ref = ReflectionReference::fromArrayElement([&$var], 0)->getId();
if (isset($this->arr_ref_stack[$ref])) {
debug_print_backtrace();
return true;
}
$this->arr_ref_stack[$ref] = true;
$copy = $val;
break;
default:
return false;
}
$recurse = false;
foreach ($copy as $k => $_) {
if ($this->detect($copy[$k])) {
$recurse = true;
break;
}
}
switch (gettype($val)) {
case 'object':
unset($this->obj_ref_stack[$hash]);
break;
case 'array':
unset($this->arr_ref_stack[$ref]);
break;
}
return $recurse;
}
}
$d = new RecursionDetector();
class X {
public array $y = [];
}
$x = new X();
$r = new ReflectionClass('X');
$z = $r->newLazyProxy(fn() => $x);
$x->y[] = [[$z]];
$_ = $z->y;
var_dump($x, $z);
var_dump($d->detect($x));
var_dump($d->detect($z));