diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index d62f7699d4ef..2f7b4076c694 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -206,7 +206,6 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is $f['file'] = substr($f['file'], 0, -\strlen($match[0])); $f['line'] = (int) $match[1]; } - $caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null; $src = $f['line']; $srcKey = $f['file']; $ellipsis = new LinkStub($srcKey, 0); @@ -226,13 +225,13 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is $templatePath = null; } if ($templateSrc) { - $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath); + $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f); $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; } } } if ($srcKey == $f['file']) { - $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']); + $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f); $srcKey .= ':'.$f['line']; if ($ellipsis) { $ellipsis += 1 + \strlen($f['line']); @@ -308,7 +307,7 @@ private static function traceUnshift(array &$trace, ?string $class, string $file ]); } - private static function extractSource(string $srcLines, int $line, int $srcContext, ?string $title, string $lang, string $file = null): EnumStub + private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub { $srcLines = explode("\n", $srcLines); $src = []; @@ -317,7 +316,32 @@ private static function extractSource(string $srcLines, int $line, int $srcConte $src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n"; } - $srcLines = []; + if ($frame['function'] ?? false) { + $stub = new CutStub(new \stdClass()); + $stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; + $stub->type = Stub::TYPE_OBJECT; + $stub->attr['cut_hash'] = true; + $stub->attr['file'] = $frame['file']; + $stub->attr['line'] = $frame['line']; + + try { + $caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']); + $stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE)); + + if ($f = $caller->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $caller->getStartLine(); + } + } catch (\ReflectionException $e) { + // ignore fake class/function + } + + $srcLines = ["\0~separator=\0" => $stub]; + } else { + $stub = null; + $srcLines = []; + } + $ltrim = 0; do { $pad = null; @@ -344,7 +368,7 @@ private static function extractSource(string $srcLines, int $line, int $srcConte if ($i !== $srcContext) { $c = new ConstStub('default', $c); } else { - $c = new ConstStub($c, $title); + $c = new ConstStub($c, $stub ? 'in '.$stub->class : ''); if (null !== $file) { $c->attr['file'] = $file; $c->attr['line'] = $line; diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 4206b5222cc2..7662cc8000a5 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -283,14 +283,14 @@ public function enterHash(Cursor $cursor, $type, $class, $hasChild) $class = $this->utf8Encode($class); if (Cursor::HASH_OBJECT === $type) { - $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).' {' : '{'; + $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).(empty($attr['cut_hash']) ? ' {' : '') : '{'; } elseif (Cursor::HASH_RESOURCE === $type) { $prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' '); } else { $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class, $attr).' [' : '['; } - if ($cursor->softRefCount || 0 < $cursor->softRefHandle) { + if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) { $prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]); } elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) { $prefix .= $this->style('ref', '&'.$cursor->hardRefTo, ['count' => $cursor->hardRefCount]); @@ -310,8 +310,11 @@ public function enterHash(Cursor $cursor, $type, $class, $hasChild) */ public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut) { - $this->dumpEllipsis($cursor, $hasChild, $cut); - $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : '')); + if (empty($cursor->attr['cut_hash'])) { + $this->dumpEllipsis($cursor, $hasChild, $cut); + $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : '')); + } + $this->endValue($cursor); } diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php index 1096919308b5..50c7a8d24dca 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php @@ -47,6 +47,7 @@ public function testDefaultSettings() #line: 28 trace: { %s%eTests%eCaster%eExceptionCasterTest.php:28 { + Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->getTestException($msg, &$ref = null) › { › return new \Exception(''.$msg); › } @@ -66,11 +67,12 @@ public function testSeek() $expectedDump = <<<'EODUMP' { %s%eTests%eCaster%eExceptionCasterTest.php:28 { + Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->getTestException($msg, &$ref = null) › { › return new \Exception(''.$msg); › } } - %s%eTests%eCaster%eExceptionCasterTest.php:64 { …} + %s%eTests%eCaster%eExceptionCasterTest.php:65 { …} %A EODUMP; @@ -90,11 +92,12 @@ public function testNoArgs() #line: 28 trace: { %sExceptionCasterTest.php:28 { + Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->getTestException($msg, &$ref = null) › { › return new \Exception(''.$msg); › } } - %s%eTests%eCaster%eExceptionCasterTest.php:82 { …} + %s%eTests%eCaster%eExceptionCasterTest.php:84 { …} %A EODUMP; diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index fc623808ce1d..4f3b73f43271 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -143,6 +143,7 @@ public function testDumpWithCommaFlagsAndExceptionCodeExcerpt() #line: %d trace: { %ACliDumperTest.php:%d { + Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest->testDumpWithCommaFlagsAndExceptionCodeExcerpt() › › $ex = new \RuntimeException('foo'); › @@ -382,6 +383,7 @@ public function testThrowingCaster() #message: "Unexpected Exception thrown from a caster: Foobar" trace: { %sTwig.php:2 { + __TwigTemplate_VarDumperFixture_u75a09->doDisplay(array \$context, array \$blocks = []) › foo bar › twig source ›