[VarDumper] add force-collapse/expand + use it for traces

This commit is contained in:
Nicolas Grekas 2017-08-23 23:15:08 +02:00
parent 481e31c2d1
commit 0e2d2b8c08
10 changed files with 133 additions and 109 deletions

View File

@ -127,6 +127,7 @@ class ExceptionCaster
}
$lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '';
$frames[] = array('function' => '');
$collapse = false;
for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
$f = $frames[$i];
@ -145,6 +146,13 @@ class ExceptionCaster
$f = self::castFrameStub($frame, array(), $frame, true);
if (isset($f[$prefix.'src'])) {
foreach ($f[$prefix.'src']->value as $label => $frame) {
if (0 === strpos($label, "\0~collapse=0")) {
if ($collapse) {
$label = substr_replace($label, '1', 11, 1);
} else {
$collapse = true;
}
}
$label = substr_replace($label, "title=Stack level $j.&", 2, 0);
}
$f = $frames[$i - 1];
@ -162,7 +170,7 @@ class ExceptionCaster
} else {
$label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall;
}
$a[$label] = $frame;
$a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame;
$lastCall = $call;
}
@ -197,9 +205,10 @@ class ExceptionCaster
$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))->attr;
$ellipsisTail = isset($ellipsis['ellipsis-tail']) ? $ellipsis['ellipsis-tail'] : 0;
$ellipsis = isset($ellipsis['ellipsis']) ? $ellipsis['ellipsis'] : 0;
$ellipsis = new LinkStub($srcKey, 0);
$srcAttr = 'collapse='.(int) $ellipsis->inVendor;
$ellipsisTail = isset($ellipsis->attr['ellipsis-tail']) ? $ellipsis->attr['ellipsis-tail'] : 0;
$ellipsis = isset($ellipsis->attr['ellipsis']) ? $ellipsis->attr['ellipsis'] : 0;
if (file_exists($f['file']) && 0 <= self::$srcContext) {
if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) {
@ -225,8 +234,11 @@ class ExceptionCaster
$ellipsis += 1 + strlen($f['line']);
}
}
$srcAttr .= '&separator= ';
} else {
$srcAttr .= '&separator=:';
}
$srcAttr = $ellipsis ? 'ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : '';
$srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : '';
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
}
}
@ -329,7 +341,7 @@ class ExceptionCaster
}
}
$c->attr['lang'] = $lang;
$srcLines[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
$srcLines[sprintf("\0~separator= &%d\0", $i + $line - $srcContext)] = $c;
}
return new EnumStub($srcLines);

View File

@ -18,6 +18,8 @@ namespace Symfony\Component\VarDumper\Caster;
*/
class LinkStub extends ConstStub
{
public $inVendor = false;
private static $vendorRoots;
private static $composerRoots;
@ -50,10 +52,10 @@ class LinkStub extends ConstStub
if ($label !== $this->attr['file'] = realpath($href) ?: $href) {
return;
}
if ($composerRoot = $this->getComposerRoot($href, $inVendor)) {
if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) {
$this->attr['ellipsis'] = strlen($href) - strlen($composerRoot) + 1;
$this->attr['ellipsis-type'] = 'path';
$this->attr['ellipsis-tail'] = 1 + ($inVendor ? 2 + strlen(implode(array_slice(explode(DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0);
$this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + strlen(implode(array_slice(explode(DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0);
} elseif (3 < count($ellipsis = explode(DIRECTORY_SEPARATOR, $href))) {
$this->attr['ellipsis'] = 2 + strlen(implode(array_slice($ellipsis, -2)));
$this->attr['ellipsis-type'] = 'path';

View File

@ -122,7 +122,7 @@ class ReflectionCaster
$function = new FrameStub($frame, false, true);
$function = ExceptionCaster::castFrameStub($function, array(), $function, true);
$a[$prefix.'executing'] = new EnumStub(array(
$frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'],
"\0~separator= \0".$frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'],
));
}

View File

@ -39,4 +39,5 @@ class Cursor
public $hashCut = 0;
public $stop = false;
public $attr = array();
public $skipChildren = false;
}

View File

@ -355,10 +355,16 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
$withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
$dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
if ($withChildren) {
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
if ($cursor->skipChildren) {
$withChildren = false;
$cut = -1;
} else {
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
}
} elseif ($children && 0 <= $cut) {
$cut += count($children);
}
$cursor->skipChildren = false;
$dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
break;

View File

@ -51,6 +51,9 @@ class CliDumper extends AbstractDumper
"\033" => '\e',
);
protected $collapseNextHash = false;
protected $expandNextHash = false;
/**
* {@inheritdoc}
*/
@ -253,6 +256,11 @@ class CliDumper extends AbstractDumper
{
$this->dumpKey($cursor);
if ($this->collapseNextHash) {
$cursor->skipChildren = true;
$this->collapseNextHash = $hasChild = false;
}
$class = $this->utf8Encode($class);
if (Cursor::HASH_OBJECT === $type) {
$prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{';
@ -368,7 +376,15 @@ class CliDumper extends AbstractDumper
break;
}
$this->line .= $bin.$this->style($style, $key[1], $attr).': ';
if (isset($attr['collapse'])) {
if ($attr['collapse']) {
$this->collapseNextHash = true;
} else {
$this->expandNextHash = true;
}
}
$this->line .= $bin.$this->style($style, $key[1], $attr).(isset($attr['separator']) ? $attr['separator'] : ': ');
} else {
// This case should not happen
$this->line .= '-'.$bin.'"'.$this->style('private', $key, array('class' => '')).'": ';
@ -397,6 +413,21 @@ class CliDumper extends AbstractDumper
$this->colors = $this->supportsColors();
}
if (isset($attr['ellipsis'], $attr['ellipsis-type'])) {
$prefix = substr($value, 0, -$attr['ellipsis']);
if ('cli' === PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && 0 === strpos($prefix, $_SERVER[$pwd])) {
$prefix = '.'.substr($prefix, strlen($_SERVER[$pwd]));
}
if (!empty($attr['ellipsis-tail'])) {
$prefix .= substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']);
$value = substr($value, -$attr['ellipsis'] + $attr['ellipsis-tail']);
} else {
$value = substr($value, -$attr['ellipsis']);
}
return $this->style('default', $prefix).$this->style($style, $value);
}
$style = $this->styles[$style];
$map = static::$controlCharsMap;

View File

@ -366,7 +366,6 @@ return function (root, x) {
for (i = 0; i < len; ++i) {
elt = t[i];
if ('SAMP' == elt.tagName) {
elt.className = 'sf-dump-expanded';
a = elt.previousSibling || {};
if ('A' != a.tagName) {
a = doc.createElement('A');
@ -383,7 +382,8 @@ return function (root, x) {
x += elt.parentNode.getAttribute('data-depth')/1;
}
elt.setAttribute('data-depth', x);
if (x > options.maxDepth) {
if (elt.className ? 'sf-dump-expanded' !== elt.className : (x > options.maxDepth)) {
elt.className = 'sf-dump-expanded';
toggle(a);
}
} else if ('sf-dump-ref' == elt.className && (a = elt.getAttribute('href'))) {
@ -728,15 +728,25 @@ EOHTML
{
parent::enterHash($cursor, $type, $class, false);
if ($cursor->skipChildren) {
$cursor->skipChildren = false;
$eol = ' class=sf-dump-compact>';
} elseif ($this->expandNextHash) {
$this->expandNextHash = false;
$eol = ' class=sf-dump-expanded>';
} else {
$eol = '>';
}
if ($hasChild) {
$this->line .= '<samp';
if ($cursor->refIndex) {
$r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2;
$r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex;
$this->line .= sprintf('<samp id=%s-ref%s>', $this->dumpId, $r);
} else {
$this->line .= '<samp>';
$this->line .= sprintf(' id=%s-ref%s', $this->dumpId, $r);
}
$this->line .= $eol;
$this->dumpLine($cursor->depth);
}
}

View File

@ -46,20 +46,13 @@ Exception {
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%sExceptionCasterTest.php:28: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: $ref = array('foo');
: $e = $this->getTestException('foo', $ref);
:
arguments: {
$msg: "foo"
&$ref: array:1 [ …1]
}
%s%eTests%eCaster%eExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:40 { }
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testDefaultSettings() {}
%A
EODUMP;
@ -73,19 +66,13 @@ EODUMP;
$expectedDump = <<<'EODUMP'
{
%sExceptionCasterTest.php:28: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: {
: $e = $this->getTestException(2);
:
arguments: {
$msg: 2
}
%s%eTests%eCaster%eExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:65 { }
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testSeek() {}
%A
EODUMP;
@ -104,16 +91,13 @@ Exception {
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%sExceptionCasterTest.php:28: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: {
: $e = $this->getTestException(1);
: ExceptionCaster::$traceArgs = false;
%sExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:84 { }
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testNoArgs() {}
%A
EODUMP;
@ -132,8 +116,8 @@ Exception {
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%sExceptionCasterTest.php: 28
%sExceptionCasterTest.php: %d
%s%eTests%eCaster%eExceptionCasterTest.php:28
%s%eTests%eCaster%eExceptionCasterTest.php:%d
%A
EODUMP;
@ -161,7 +145,7 @@ EODUMP;
#<span class=sf-dump-protected title="Protected property">line</span>: <span class=sf-dump-num>28</span>
<span class=sf-dump-meta>trace</span>: {<samp>
<span class=sf-dump-meta title="%sExceptionCasterTest.php
Stack level %d."><span class="sf-dump-ellipsis sf-dump-ellipsis-path">%s%eVarDumper</span><span class=sf-dump-ellipsis>%e</span>Tests%eCaster%eExceptionCasterTest.php</span>: <span class=sf-dump-num>28</span>
Stack level %d."><span class="sf-dump-ellipsis sf-dump-ellipsis-path">%s%eVarDumper</span><span class=sf-dump-ellipsis>%e</span>Tests%eCaster%eExceptionCasterTest.php</span>:<span class=sf-dump-num>28</span>
&hellip;%d
</samp>}
</samp>}
@ -197,10 +181,10 @@ array:2 [
0 => {
class: "__TwigTemplate_VarDumperFixture_u75a09"
src: {
%sTwig.php:1: {
:
: foo bar
: twig source
%sTwig.php:1 {
foo bar
twig source
}
}
}
@ -210,10 +194,10 @@ array:2 [
%A
}
src: {
%sExceptionCasterTest.php:2: {
: foo bar
: twig source
:
%sExceptionCasterTest.php:2 {
foo bar
twig source
}
}
}

View File

@ -174,11 +174,11 @@ EOTXT
Generator {
this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { }
executing: {
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz(): {
%sGeneratorDemo.php:14: {
: {
: yield from bar();
: }
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {
%sGeneratorDemo.php:14 {
{
yield from bar();
}
}
}
}
@ -197,31 +197,23 @@ array:2 [
0 => ReflectionGenerator {
this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { }
trace: {
%sGeneratorDemo.php:9: {
: {
: yield 1;
: }
}
%sGeneratorDemo.php:20: {
: {
: yield from GeneratorDemo::foo();
: }
}
%sGeneratorDemo.php:14: {
: {
: yield from bar();
: }
%s%eTests%eFixtures%eGeneratorDemo.php:9 {
{
yield 1;
}
}
%s%eTests%eFixtures%eGeneratorDemo.php:20 { }
%s%eTests%eFixtures%eGeneratorDemo.php:14 { }
}
closed: false
}
1 => Generator {
executing: {
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): {
%sGeneratorDemo.php:10: {
: yield 1;
: }
:
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() {
%sGeneratorDemo.php:10 {
yield 1;
}
}
}
}

View File

@ -86,7 +86,7 @@ array:24 [
default: null
}
}
file: "{$var['file']}"
file: "%s%eTests%eFixtures%edumb-var.php"
line: "{$var['line']} to {$var['line']}"
}
"line" => {$var['line']}
@ -361,30 +361,16 @@ stream resource {@{$ref}
: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
#message: "Unexpected Exception thrown from a caster: Foobar"
trace: {
%sTwig.php:2: {
: foo bar
: twig source
:
%sTwig.php:2 {
foo bar
twig source
}
%sTemplate.php:%d: {
: try {
: \$this->doDisplay(\$context, \$blocks);
: } catch (Twig%sError \$e) {
}
%sTemplate.php:%d: {
: {
: \$this->displayWithErrorHandling(\$this->env->mergeGlobals(\$context), array_merge(\$this->blocks, \$blocks));
: }
}
%sTemplate.php:%d: {
: try {
: \$this->display(\$context);
: } catch (%s \$e) {
}
%sCliDumperTest.php:%d: {
%A
}
}
%s%eTemplate.php:%d { }
%s%eTemplate.php:%d { }
%s%eTemplate.php:%d { }
%s%eTests%eDumper%eCliDumperTest.php:%d { }
%A }
}
%Awrapper_type: "PHP"
stream_type: "MEMORY"