Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dace4a0

Browse files
ktheragenicolas-grekas
authored andcommitted
[VarDumper] Output the location of calls to dump()
1 parent 0f1ad9b commit dace4a0

File tree

6 files changed

+219
-8
lines changed

6 files changed

+219
-8
lines changed

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\VarDumper\Cloner;
1313

1414
use Symfony\Component\VarDumper\Caster\Caster;
15+
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
1516

1617
/**
1718
* @author Nicolas Grekas <[email protected]>
@@ -24,6 +25,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
2425
private $maxDepth = 20;
2526
private $maxItemsPerDepth = -1;
2627
private $useRefHandles = -1;
28+
private $context = [];
2729

2830
/**
2931
* @param array $data An array as returned by ClonerInterface::cloneVar()
@@ -168,7 +170,7 @@ public function __toString()
168170
*
169171
* @param int $maxDepth The max dumped depth level
170172
*
171-
* @return self A clone of $this
173+
* @return static A clone of $this
172174
*/
173175
public function withMaxDepth($maxDepth)
174176
{
@@ -183,7 +185,7 @@ public function withMaxDepth($maxDepth)
183185
*
184186
* @param int $maxItemsPerDepth The max number of items dumped per depth level
185187
*
186-
* @return self A clone of $this
188+
* @return static A clone of $this
187189
*/
188190
public function withMaxItemsPerDepth($maxItemsPerDepth)
189191
{
@@ -198,7 +200,7 @@ public function withMaxItemsPerDepth($maxItemsPerDepth)
198200
*
199201
* @param bool $useRefHandles False to hide global ref. handles
200202
*
201-
* @return self A clone of $this
203+
* @return static A clone of $this
202204
*/
203205
public function withRefHandles($useRefHandles)
204206
{
@@ -208,12 +210,23 @@ public function withRefHandles($useRefHandles)
208210
return $data;
209211
}
210212

213+
/**
214+
* @return static A clone of $this
215+
*/
216+
public function withContext(array $context)
217+
{
218+
$data = clone $this;
219+
$data->context = $context;
220+
221+
return $data;
222+
}
223+
211224
/**
212225
* Seeks to a specific key in nested data structures.
213226
*
214227
* @param string|int $key The key to seek to
215228
*
216-
* @return self|null A clone of $this or null if the key is not set
229+
* @return static|null A clone of $this or null if the key is not set
217230
*/
218231
public function seek($key)
219232
{
@@ -262,7 +275,18 @@ public function seek($key)
262275
public function dump(DumperInterface $dumper)
263276
{
264277
$refs = [0];
265-
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
278+
$cursor = new Cursor();
279+
280+
if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
281+
$cursor->attr['if_links'] = true;
282+
$cursor->hashType = -1;
283+
$dumper->dumpScalar($cursor, 'default', '^');
284+
$cursor->attr = ['if_links' => true];
285+
$dumper->dumpScalar($cursor, 'default', ' ');
286+
$cursor->hashType = 0;
287+
}
288+
289+
$this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
266290
}
267291

268292
/**

src/Symfony/Component/VarDumper/Dumper/CliDumper.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public function __construct($output = null, string $charset = null, int $flags =
8383
]);
8484
}
8585

86-
$this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f';
86+
$this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l';
8787
}
8888

8989
/**
@@ -493,6 +493,8 @@ protected function style($style, $value, $attr = [])
493493
if (isset($attr['href'])) {
494494
$value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\";
495495
}
496+
} elseif ($attr['if_links'] ?? false) {
497+
return '';
496498
}
497499

498500
return $value;
@@ -551,6 +553,10 @@ protected function dumpLine($depth, $endOfValue = false)
551553

552554
protected function endValue(Cursor $cursor)
553555
{
556+
if (-1 === $cursor->hashType) {
557+
return;
558+
}
559+
554560
if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) {
555561
if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) {
556562
$this->line .= ',';
@@ -635,7 +641,7 @@ private function isWindowsTrueColor()
635641
private function getSourceLink($file, $line)
636642
{
637643
if ($fmt = $this->displayOptions['fileLinkFormat']) {
638-
return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file);
644+
return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line);
639645
}
640646

641647
return false;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarDumper\Dumper;
13+
14+
use Symfony\Component\VarDumper\Cloner\Data;
15+
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
16+
17+
/**
18+
* @author Kévin Thérage <[email protected]>
19+
*/
20+
class ContextualizedDumper implements DataDumperInterface
21+
{
22+
private $wrappedDumper;
23+
private $contextProviders;
24+
25+
/**
26+
* @param ContextProviderInterface[] $contextProviders
27+
*/
28+
public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders)
29+
{
30+
$this->wrappedDumper = $wrappedDumper;
31+
$this->contextProviders = $contextProviders;
32+
}
33+
34+
public function dump(Data $data)
35+
{
36+
$context = [];
37+
foreach ($this->contextProviders as $contextProvider) {
38+
$context[\get_class($contextProvider)] = $contextProvider->getContext();
39+
}
40+
41+
$this->wrappedDumper->dump($data->withContext($context));
42+
}
43+
}

src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ public function testMaxIntBoundary()
5252
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
5353
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
5454
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
55+
[context:Symfony\Component\VarDumper\Cloner\Data:private] => Array
56+
(
57+
)
58+
5559
)
5660
5761
EOTXT;
@@ -140,6 +144,10 @@ public function testClone()
140144
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
141145
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
142146
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
147+
[context:Symfony\Component\VarDumper\Cloner\Data:private] => Array
148+
(
149+
)
150+
143151
)
144152
145153
EOTXT;
@@ -308,6 +316,10 @@ public function testLimits()
308316
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
309317
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
310318
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
319+
[context:Symfony\Component\VarDumper\Cloner\Data:private] => Array
320+
(
321+
)
322+
311323
)
312324
313325
EOTXT;
@@ -326,7 +338,7 @@ public function testJsonCast()
326338
$clone = $cloner->cloneVar($data);
327339

328340
$expected = <<<'EOTXT'
329-
object(Symfony\Component\VarDumper\Cloner\Data)#%i (6) {
341+
object(Symfony\Component\VarDumper\Cloner\Data)#%d (7) {
330342
["data":"Symfony\Component\VarDumper\Cloner\Data":private]=>
331343
array(2) {
332344
[0]=>
@@ -371,6 +383,9 @@ public function testJsonCast()
371383
int(-1)
372384
["useRefHandles":"Symfony\Component\VarDumper\Cloner\Data":private]=>
373385
int(-1)
386+
["context":"Symfony\Component\VarDumper\Cloner\Data":private]=>
387+
array(0) {
388+
}
374389
}
375390

376391
EOTXT;
@@ -431,6 +446,10 @@ public function testCaster()
431446
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
432447
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
433448
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
449+
[context:Symfony\Component\VarDumper\Cloner\Data:private] => Array
450+
(
451+
)
452+
434453
)
435454
436455
EOTXT;
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\VarDumper\Tests\Dumper;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\VarDumper\Cloner\VarCloner;
16+
use Symfony\Component\VarDumper\Dumper\CliDumper;
17+
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
18+
use Symfony\Component\VarDumper\Dumper\ContextualizedDumper;
19+
20+
/**
21+
* @author Kévin Thérage <[email protected]>
22+
*/
23+
class ContextualizedDumperTest extends TestCase
24+
{
25+
public function testContextualizedCliDumper(): void
26+
{
27+
require __DIR__.'/../Fixtures/dumb-var.php';
28+
$wrappedDumper = new CliDumper('php://output');
29+
$wrappedDumper->setColors(false);
30+
31+
$dumper = new ContextualizedDumper($wrappedDumper, [
32+
'source_context' => new class() implements ContextProviderInterface {
33+
public function getContext(): ?array
34+
{
35+
return [
36+
'file' => '/home/example.php',
37+
'line' => 42,
38+
];
39+
}
40+
},
41+
]);
42+
$cloner = new VarCloner();
43+
$cloner->addCasters([
44+
':stream' => function ($res, $a) {
45+
unset($a['uri'], $a['wrapper_data']);
46+
47+
return $a;
48+
},
49+
]);
50+
$data = $cloner->cloneVar($var);
51+
52+
ob_start();
53+
$dumper->dump($data);
54+
$out = ob_get_clean();
55+
$out = preg_replace('/[ \t]+$/m', '', $out);
56+
$intMax = PHP_INT_MAX;
57+
$res = (int) $var['res'];
58+
59+
$this->assertStringMatchesFormat(
60+
<<<EOTXT
61+
array:24 [ ]8;;file:///home/example.php\[^]]8;;\
62+
"number" => 1
63+
0 => &1 null
64+
"const" => 1.1
65+
1 => true
66+
2 => false
67+
3 => NAN
68+
4 => INF
69+
5 => -INF
70+
6 => {$intMax}
71+
"str" => "déjà\\n"
72+
7 => b"""
73+
é\\x00test\\t\\n
74+
ing
75+
"""
76+
"[]" => []
77+
"res" => stream resource {@{$res}
78+
%A wrapper_type: "plainfile"
79+
stream_type: "STDIO"
80+
mode: "r"
81+
unread_bytes: 0
82+
seekable: true
83+
%A options: []
84+
}
85+
"obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d
86+
+foo: "foo"
87+
+"bar": "bar"
88+
}
89+
"closure" => Closure(\$a, PDO &\$b = null) {#%d
90+
class: "Symfony\Component\VarDumper\Tests\Dumper\ContextualizedDumperTest"
91+
this: Symfony\Component\VarDumper\Tests\Dumper\ContextualizedDumperTest {#%d …}
92+
file: "%s%eTests%eFixtures%edumb-var.php"
93+
line: "{$var['line']} to {$var['line']}"
94+
}
95+
"line" => {$var['line']}
96+
"nobj" => array:1 [
97+
0 => &3 {#%d}
98+
]
99+
"recurs" => &4 array:1 [
100+
0 => &4 array:1 [&4]
101+
]
102+
8 => &1 null
103+
"sobj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d}
104+
"snobj" => &3 {#%d}
105+
"snobj2" => {#%d}
106+
"file" => "{$var['file']}"
107+
b"bin-key-é" => ""
108+
]
109+
110+
EOTXT
111+
,
112+
$out
113+
);
114+
}
115+
}

src/Symfony/Component/VarDumper/VarDumper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
1515
use Symfony\Component\VarDumper\Cloner\VarCloner;
1616
use Symfony\Component\VarDumper\Dumper\CliDumper;
17+
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
18+
use Symfony\Component\VarDumper\Dumper\ContextualizedDumper;
1719
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
1820

1921
// Load the global dump() function
@@ -38,6 +40,8 @@ public static function dump($var)
3840
$dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
3941
}
4042

43+
$dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]);
44+
4145
self::$handler = function ($var) use ($cloner, $dumper) {
4246
$dumper->dump($cloner->cloneVar($var));
4347
};

0 commit comments

Comments
 (0)