3v4l.org

run code in 300+ PHP versions simultaneously
<?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));

preferences:
34.62 ms | 406 KiB | 5 Q