diff --git a/src/Tracy/Dumper/Describer.php b/src/Tracy/Dumper/Describer.php index 733de6c07..103f2ad09 100644 --- a/src/Tracy/Dumper/Describer.php +++ b/src/Tracy/Dumper/Describer.php @@ -43,13 +43,16 @@ class Describer /** @var int[] */ private $references = []; + /** @var int[] */ + private $parentArrays = []; + /** * @return mixed */ - public function describe(&$var) + public function describe($var) { - $this->references = []; + $this->references = $this->parentArrays = []; uksort($this->objectExposers, function ($a, $b): int { return $b === '' || (class_exists($a, false) && is_subclass_of($a, $b)) ? -1 : 1; }); @@ -60,7 +63,7 @@ public function describe(&$var) /** * @return mixed */ - private function describeVar(&$var, int $depth = 0) + private function describeVar($var, int $depth = 0, int $refId = null) { switch (true) { case $var === null: @@ -80,6 +83,15 @@ private function describeVar(&$var, int $depth = 0) } return (object) ['string' => $s, 'length' => strlen($var)]; + case is_array($var) && $refId: + if (in_array($refId, $this->parentArrays, true)) { + return (object) ['stop' => [count($var), true]]; + } + $this->parentArrays[] = $refId; + $res = $this->describeArray($var, $depth); + array_pop($this->parentArrays); + return $res; + case is_array($var): return $this->describeArray($var, $depth); @@ -100,29 +112,18 @@ private function describeVar(&$var, int $depth = 0) */ private function describeArray(array &$arr, int $depth = 0) { - static $marker; - if ($marker === null) { - $marker = uniqid("\x00", true); - } - if (count($arr) && (isset($arr[$marker]) || $depth >= $this->maxDepth)) { - return (object) ['stop' => [count($arr) - isset($arr[$marker]), isset($arr[$marker])]]; + if (count($arr) && $depth >= $this->maxDepth) { + return (object) ['stop' => [count($arr), false]]; } $res = []; - try { - $arr[$marker] = true; - foreach ($arr as $k => $v) { - if ($k !== $marker) { - $refId = $this->getReferenceId($arr, $k); - $res[] = [ - $this->encodeKey($k), - is_string($k) && isset($this->keysToHide[strtolower($k)]) - ? (object) ['key' => self::hideValue($v)] - : $this->describeVar($arr[$k], $depth + 1), - ] + ($refId ? [2 => $refId] : []); - } - } - } finally { - unset($arr[$marker]); + foreach ($arr as $k => $v) { + $refId = $this->getReferenceId($arr, $k); + $res[] = [ + $this->encodeKey($k), + is_string($k) && isset($this->keysToHide[strtolower($k)]) + ? (object) ['key' => self::hideValue($v)] + : $this->describeVar($arr[$k], $depth + 1, $refId), + ] + ($refId ? [2 => $refId] : []); } return $res; }