diff --git a/build/kint.phar b/build/kint.phar index ccebe819..9e87b9ce 100644 Binary files a/build/kint.phar and b/build/kint.phar differ diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index e9715fa5..96cefb3e 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -85,6 +85,7 @@ class Parser protected array $array_ref_stack = []; protected array $object_hashes = []; protected array $plugins = []; + protected bool $in_parse = false; /** * @param int $depth_limit Maximum depth to parse data @@ -105,7 +106,7 @@ public function __construct(int $depth_limit = 0, ?string $caller = null) */ public function setCallerClass(?string $caller = null): void { - $this->noRecurseCall(); + $this->noCallInParse(); $this->caller_class = $caller; } @@ -123,7 +124,7 @@ public function getCallerClass(): ?string */ public function setDepthLimit(int $depth_limit = 0): void { - $this->noRecurseCall(); + $this->noCallInParse(); $this->depth_limit = $depth_limit; } @@ -140,39 +141,49 @@ public function getDepthLimit(): int */ public function parse(&$var, ContextInterface $c): AbstractValue { - $type = \strtolower(\gettype($var)); + $in_parse_stash = $this->in_parse; - if ($v = $this->applyPluginsBegin($var, $c, $type)) { - return $v; - } + try { + $this->in_parse = true; + + $type = \strtolower(\gettype($var)); + + if ($v = $this->applyPluginsBegin($var, $c, $type)) { + return $v; + } - switch ($type) { - case 'array': - return $this->parseArray($var, $c); - case 'boolean': - case 'double': - case 'integer': - case 'null': - return $this->parseFixedWidth($var, $c); - case 'object': - return $this->parseObject($var, $c); - case 'resource': - return $this->parseResource($var, $c); - case 'string': - return $this->parseString($var, $c); - case 'resource (closed)': - return $this->parseResourceClosed($var, $c); - - case 'unknown type': // @codeCoverageIgnore - default: - // These should never happen. Unknown is resource (closed) from old - // PHP versions and there shouldn't be any other types. - return $this->parseUnknown($var, $c); // @codeCoverageIgnore + switch ($type) { + case 'array': + return $this->parseArray($var, $c); + case 'boolean': + case 'double': + case 'integer': + case 'null': + return $this->parseFixedWidth($var, $c); + case 'object': + return $this->parseObject($var, $c); + case 'resource': + return $this->parseResource($var, $c); + case 'string': + return $this->parseString($var, $c); + case 'resource (closed)': + return $this->parseResourceClosed($var, $c); + + case 'unknown type': // @codeCoverageIgnore + default: + // These should never happen. Unknown is resource (closed) from old + // PHP versions and there shouldn't be any other types. + return $this->parseUnknown($var, $c); // @codeCoverageIgnore + } + } finally { + $this->in_parse = $in_parse_stash; } } public function addPlugin(PluginInterface $p): void { + $this->noCallInParse(); + if (!$types = $p->getTypes()) { return; } @@ -209,25 +220,33 @@ public function addPlugin(PluginInterface $p): void public function clearPlugins(): void { + $this->noCallInParse(); + $this->plugins = []; } + /** + * @psalm-api + * + * @codeCoverageIgnore + * + * @deprecated Use noCallInParse + */ protected function noRecurseCall(): void { - $bt = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS); + \trigger_error('Kint\\Parser::noRecurseCall is deprecated and will be removed in Kint 7. Use noCallInParse instead.', E_USER_DEPRECATED); - $caller_frame = [ - 'function' => __FUNCTION__, - ]; + $this->noCallInParse(); + } - while (isset($bt[0]['object']) && $bt[0]['object'] === $this) { - $caller_frame = \array_shift($bt); - } + final protected function noCallInParse(): void + { + if ($this->in_parse) { + $bt = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS); + $caller_frame = \reset($bt); - foreach ($bt as $frame) { - if (isset($frame['object']) && $frame['object'] === $this) { - throw new DomainException(__CLASS__.'::'.$caller_frame['function'].' cannot be called from inside a parse'); - } + /** @psalm-var class-string $caller_frame['class'] */ + throw new DomainException($caller_frame['class'].'::'.$caller_frame['function'].' cannot be called from inside a parse'); } } diff --git a/tests/Parser/ParserTest.php b/tests/Parser/ParserTest.php index cfba31be..b79b265f 100644 --- a/tests/Parser/ParserTest.php +++ b/tests/Parser/ParserTest.php @@ -121,9 +121,9 @@ public function testSetDepthLimit() } /** - * @covers \Kint\Parser\Parser::noRecurseCall + * @covers \Kint\Parser\Parser::noCallInParse */ - public function testNoRecurseCall() + public function testNoCallInParse() { $p = new Parser(); $p->setDepthLimit(42); @@ -150,9 +150,9 @@ function (&$var, $v) use ($p2) { } /** - * @covers \Kint\Parser\Parser::noRecurseCall + * @covers \Kint\Parser\Parser::noCallInParse */ - public function testNoRecurseCallWithRecursion() + public function testNoCallInParseWithRecursion() { $p = new Parser(); $p->setDepthLimit(42);