Skip to content

Commit 0e6465a

Browse files
committed
bug #12202 [VarDumper] enhance dumping refs (nicolas-grekas)
This PR was merged into the 2.6-dev branch. Discussion ---------- [VarDumper] enhance dumping refs | Q | A | ------------- | --- | Bug fix? | yes | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | nicolas-grekas/Patchwork-Dumper#39 | License | MIT | Doc PR | - This makes dumps prettier: - VarCloner now exposes the "isref" state of a PHP variable - on hard refs, `#n` suffix is replaced by `&n` prefix - `#n`/`@n` (object/resource refs) are moved inside the `{ }` - all repetitive dumps of the same object are toggle-able - all repetitive dumps of the same object / hard ref are *visually* identical - dumps expose local ref counts and object's handle I also simplified the `Cloner\DumperInterface`. For the same (circumvoluted) variable: Before: ![before](https://cloud.githubusercontent.com/assets/243674/4595026/f6b2a98c-5094-11e4-9fe0-dc6d24da3f14.png) After: ![after](https://cloud.githubusercontent.com/assets/243674/4595035/07e04980-5095-11e4-9e45-54a1e7453547.png) Commits ------- 3c401af [VarDumper] enhance dumping refs
2 parents 8e42756 + 3c401af commit 0e6465a

File tree

13 files changed

+380
-367
lines changed

13 files changed

+380
-367
lines changed

src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php

+6-6
Original file line numberDiff line numberDiff line change
@@ -86,20 +86,20 @@ public function getDumpArgs()
8686
{
8787
return array(
8888
array(array(), array(), '', false),
89-
array(array(), array(), "<pre class=sf-dump>[]\n</pre><script>Sfdump.instrument()</script>\n"),
89+
array(array(), array(), "<pre class=sf-dump id=sf-dump data-indent-pad=\" \">[]\n</pre><script>Sfdump(\"sf-dump\")</script>\n"),
9090
array(
9191
array(),
9292
array(123, 456),
93-
"<pre class=sf-dump><span class=sf-dump-num>123</span>\n</pre><script>Sfdump.instrument()</script>\n"
94-
."<pre class=sf-dump><span class=sf-dump-num>456</span>\n</pre><script>Sfdump.instrument()</script>\n",
93+
"<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>123</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n"
94+
."<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>456</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n",
9595
),
9696
array(
9797
array('foo' => 'bar'),
9898
array(),
99-
"<pre class=sf-dump><span class=sf-dump-note>array:1</span> [<span name=sf-dump-child>\n"
99+
"<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-note>array:1</span> [<samp>\n"
100100
." \"<span class=sf-dump-meta>foo</span>\" => \"<span class=sf-dump-str>bar</span>\"\n"
101-
."</span>]\n"
102-
."</pre><script>Sfdump.instrument()</script>\n",
101+
."</samp>]\n"
102+
."</pre><script>Sfdump(\"sf-dump\")</script>\n",
103103
),
104104
);
105105
}

src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ public function testDump()
3535
$dump = $collector->getDumps('html');
3636
$this->assertTrue(isset($dump[0]['data']));
3737
$dump[0]['data'] = preg_replace('/^.*?<pre/', '<pre', $dump[0]['data']);
38+
$dump[0]['data'] = preg_replace('/sf-dump-\d+/', 'sf-dump', $dump[0]['data']);
3839

3940
$xDump = array(
4041
array(
41-
'data' => "<pre class=sf-dump><span class=sf-dump-num>123</span>\n</pre><script>Sfdump.instrument()</script>\n",
42+
'data' => "<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>123</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n",
4243
'name' => 'DumpDataCollectorTest.php',
4344
'file' => __FILE__,
4445
'line' => $line,

src/Symfony/Component/VarDumper/Caster/CasterStub.php

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public function __construct($value, $class = '')
4141
case 'resource':
4242
case 'unknown type':
4343
$this->type = self::TYPE_RESOURCE;
44+
$this->handle = (int) $value;
4445
$this->class = @get_resource_type($value);
4546
$this->cut = -1;
4647
break;

src/Symfony/Component/VarDumper/Caster/StubCaster.php

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static function castStub(CasterStub $c, array $a, Stub $stub, $isNested)
2626
$stub->type = $c->type;
2727
$stub->class = $c->class;
2828
$stub->value = $c->value;
29+
$stub->handle = $c->handle;
2930
$stub->cut = $c->cut;
3031

3132
return array();

src/Symfony/Component/VarDumper/Cloner/Cursor.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,13 @@ class Cursor
2424
const HASH_RESOURCE = Stub::TYPE_RESOURCE;
2525

2626
public $depth = 0;
27-
public $refIndex = false;
28-
public $softRefTo = false;
29-
public $hardRefTo = false;
27+
public $refIndex = 0;
28+
public $softRefTo = 0;
29+
public $softRefCount = 0;
30+
public $softRefHandle = 0;
31+
public $hardRefTo = 0;
32+
public $hardRefCount = 0;
33+
public $hardRefHandle = 0;
3034
public $hashType;
3135
public $hashKey;
3236
public $hashIndex = 0;

src/Symfony/Component/VarDumper/Cloner/Data.php

+27-31
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function getLimitedClone($maxDepth, $maxItemsPerDepth)
5959
public function dump(DumperInterface $dumper)
6060
{
6161
$refs = array(0);
62-
$this->dumpItem($dumper, new Cursor, $refs, $this->data[0][0]);
62+
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[0][0]);
6363
}
6464

6565
/**
@@ -72,40 +72,41 @@ public function dump(DumperInterface $dumper)
7272
*/
7373
private function dumpItem($dumper, $cursor, &$refs, $item)
7474
{
75-
$cursor->refIndex = $cursor->softRefTo = $cursor->hardRefTo = false;
75+
$cursor->refIndex = 0;
76+
$cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
77+
$cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
78+
$firstSeen = true;
7679

7780
if (!$item instanceof Stub) {
7881
$type = gettype($item);
7982
} elseif (Stub::TYPE_REF === $item->type) {
80-
if ($item->ref) {
81-
if (isset($refs[$r = $item->ref])) {
82-
$cursor->hardRefTo = $refs[$r];
83+
if ($item->handle) {
84+
if (!isset($refs[$r = $item->handle - (PHP_INT_MAX >> 1)])) {
85+
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
8386
} else {
84-
$cursor->refIndex = $refs[$r] = ++$refs[0];
87+
$firstSeen = false;
8588
}
89+
$cursor->hardRefTo = $refs[$r];
90+
$cursor->hardRefHandle = $item->handle;
91+
$cursor->hardRefCount = $item->refCount;
8692
}
8793
$type = $item->class ?: gettype($item->value);
8894
$item = $item->value;
8995
}
9096
if ($item instanceof Stub) {
91-
if ($item->ref) {
92-
if (isset($refs[$r = $item->ref])) {
93-
if (Stub::TYPE_ARRAY === $item->type) {
94-
if (false === $cursor->hardRefTo) {
95-
$cursor->hardRefTo = $refs[$r];
96-
}
97-
} elseif (false === $cursor->softRefTo) {
98-
$cursor->softRefTo = $refs[$r];
99-
}
100-
} elseif (false !== $cursor->refIndex) {
101-
$refs[$r] = $cursor->refIndex;
97+
if ($item->refCount) {
98+
if (!isset($refs[$r = $item->handle])) {
99+
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
102100
} else {
103-
$cursor->refIndex = $refs[$r] = ++$refs[0];
101+
$firstSeen = false;
104102
}
103+
$cursor->softRefTo = $refs[$r];
105104
}
105+
$cursor->softRefHandle = $item->handle;
106+
$cursor->softRefCount = $item->refCount;
106107
$cut = $item->cut;
107108

108-
if ($item->position && false === $cursor->softRefTo && false === $cursor->hardRefTo) {
109+
if ($item->position && $firstSeen) {
109110
$children = $this->data[$item->position];
110111

111112
if ($cursor->stop) {
@@ -123,29 +124,24 @@ private function dumpItem($dumper, $cursor, &$refs, $item)
123124
break;
124125

125126
case Stub::TYPE_ARRAY:
126-
$dumper->enterArray($cursor, $item->value, Stub::ARRAY_INDEXED === $item->class, (bool) $children);
127+
$dumper->enterHash($cursor, $item->class, $item->value, (bool) $children);
127128
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->class);
128-
$dumper->leaveArray($cursor, $item->value, Stub::ARRAY_INDEXED === $item->class, (bool) $children, $cut);
129+
$dumper->leaveHash($cursor, $item->class, $item->value, (bool) $children, $cut);
129130
break;
130131

131132
case Stub::TYPE_OBJECT:
132-
$dumper->enterObject($cursor, $item->class, (bool) $children);
133-
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, Cursor::HASH_OBJECT);
134-
$dumper->leaveObject($cursor, $item->class, (bool) $children, $cut);
135-
break;
136-
137133
case Stub::TYPE_RESOURCE:
138-
$dumper->enterResource($cursor, $item->class, (bool) $children);
139-
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, Cursor::HASH_RESOURCE);
140-
$dumper->leaveResource($cursor, $item->class, (bool) $children, $cut);
134+
$dumper->enterHash($cursor, $item->type, $item->class, (bool) $children);
135+
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type);
136+
$dumper->leaveHash($cursor, $item->type, $item->class, (bool) $children, $cut);
141137
break;
142138

143139
default:
144140
throw new \RuntimeException(sprintf('Unexpected Stub type: %s', $item->type));
145141
}
146142
} elseif ('array' === $type) {
147-
$dumper->enterArray($cursor, 0, true, 0, 0);
148-
$dumper->leaveArray($cursor, 0, true, 0, 0);
143+
$dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
144+
$dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
149145
} else {
150146
$dumper->dumpScalar($cursor, $type, $item);
151147
}

src/Symfony/Component/VarDumper/Cloner/DumperInterface.php

+11-49
Original file line numberDiff line numberDiff line change
@@ -38,61 +38,23 @@ public function dumpScalar(Cursor $cursor, $type, $value);
3838
public function dumpString(Cursor $cursor, $str, $bin, $cut);
3939

4040
/**
41-
* Dumps while entering an array.
41+
* Dumps while entering an hash.
4242
*
4343
* @param Cursor $cursor The Cursor position in the dump.
44-
* @param int $count The number of items in the original array.
45-
* @param bool $indexed When the array is indexed or associative.
46-
* @param bool $hasChild When the dump of the array has child item.
44+
* @param int $type A Cursor::HASH_* const for the type of hash.
45+
* @param string $class The object class, resource type or array count.
46+
* @param bool $hasChild When the dump of the hash has child item.
4747
*/
48-
public function enterArray(Cursor $cursor, $count, $indexed, $hasChild);
48+
public function enterHash(Cursor $cursor, $type, $class, $hasChild);
4949

5050
/**
51-
* Dumps while leaving an array.
51+
* Dumps while leaving an hash.
5252
*
5353
* @param Cursor $cursor The Cursor position in the dump.
54-
* @param int $count The number of items in the original array.
55-
* @param bool $indexed Whether the array is indexed or associative.
56-
* @param bool $hasChild When the dump of the array has child item.
57-
* @param int $cut The number of items the array has been cut by.
54+
* @param int $type A Cursor::HASH_* const for the type of hash.
55+
* @param string $class The object class, resource type or array count.
56+
* @param bool $hasChild When the dump of the hash has child item.
57+
* @param int $cut The number of items the hash has been cut by.
5858
*/
59-
public function leaveArray(Cursor $cursor, $count, $indexed, $hasChild, $cut);
60-
61-
/**
62-
* Dumps while entering an object.
63-
*
64-
* @param Cursor $cursor The Cursor position in the dump.
65-
* @param string $class The class of the object.
66-
* @param bool $hasChild When the dump of the object has child item.
67-
*/
68-
public function enterObject(Cursor $cursor, $class, $hasChild);
69-
70-
/**
71-
* Dumps while leaving an object.
72-
*
73-
* @param Cursor $cursor The Cursor position in the dump.
74-
* @param string $class The class of the object.
75-
* @param bool $hasChild When the dump of the object has child item.
76-
* @param int $cut The number of items the object has been cut by.
77-
*/
78-
public function leaveObject(Cursor $cursor, $class, $hasChild, $cut);
79-
80-
/**
81-
* Dumps while entering a resource.
82-
*
83-
* @param Cursor $cursor The Cursor position in the dump.
84-
* @param string $res The resource type.
85-
* @param bool $hasChild When the dump of the resource has child item.
86-
*/
87-
public function enterResource(Cursor $cursor, $res, $hasChild);
88-
89-
/**
90-
* Dumps while leaving a resource.
91-
*
92-
* @param Cursor $cursor The Cursor position in the dump.
93-
* @param string $res The resource type.
94-
* @param bool $hasChild When the dump of the resource has child item.
95-
* @param int $cut The number of items the resource has been cut by.
96-
*/
97-
public function leaveResource(Cursor $cursor, $res, $hasChild, $cut);
59+
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
9860
}

src/Symfony/Component/VarDumper/Cloner/Stub.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Stub
3434
public $class = '';
3535
public $value;
3636
public $cut = 0;
37-
public $ref = 0;
37+
public $handle = 0;
38+
public $refCount = 0;
3839
public $position = 0;
3940
}

0 commit comments

Comments
 (0)