Skip to content

Commit 74b5287

Browse files
[VarDumper] Add an options builder to configure VarDumper's behaviour at runtime
1 parent 68f27ef commit 74b5287

File tree

13 files changed

+541
-88
lines changed

13 files changed

+541
-88
lines changed

.github/expected-missing-return-types.diff

Lines changed: 61 additions & 61 deletions
Large diffs are not rendered by default.

src/Symfony/Bundle/DebugBundle/Resources/config/services.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor;
2323
use Symfony\Component\VarDumper\Command\ServerDumpCommand;
2424
use Symfony\Component\VarDumper\Dumper\CliDumper;
25+
use Symfony\Component\VarDumper\Dumper\ContextProvider\BacktraceContextProvider;
2526
use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider;
2627
use Symfony\Component\VarDumper\Dumper\ContextProvider\RequestContextProvider;
2728
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
@@ -87,6 +88,10 @@
8788
param('kernel.project_dir'),
8889
service('debug.file_link_formatter')->nullOnInvalid(),
8990
]),
91+
'backtrace' => inline_service(BacktraceContextProvider::class)->args([
92+
0,
93+
service('var_dump.cloner')->nullOnInvalid(),
94+
]),
9095
],
9196
])
9297

@@ -111,6 +116,10 @@
111116
]),
112117
'request' => inline_service(RequestContextProvider::class)->args([service('request_stack')]),
113118
'cli' => inline_service(CliContextProvider::class),
119+
'backtrace' => inline_service(BacktraceContextProvider::class)->args([
120+
0,
121+
service('var_dump.cloner')->nullOnInvalid(),
122+
]),
114123
],
115124
])
116125

src/Symfony/Bundle/DebugBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
2222
"symfony/http-kernel": "^5.4|^6.0|^7.0",
2323
"symfony/twig-bridge": "^5.4|^6.0|^7.0",
24-
"symfony/var-dumper": "^5.4|^6.0|^7.0"
24+
"symfony/var-dumper": "^6.3|^7.0"
2525
},
2626
"require-dev": {
2727
"symfony/config": "^5.4|^6.0|^7.0",

src/Symfony/Component/VarDumper/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ CHANGELOG
88
* Add support of named arguments to `dd()` and `dump()` to display the argument name
99
* Add support for `Relay\Relay`
1010
* Add display of invisible characters
11+
* Add support of options when using `dd()` and `dump()`
1112

1213
6.2
1314
---

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

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

1414
use Symfony\Component\VarDumper\Caster\Caster;
15+
use Symfony\Component\VarDumper\Dumper\ContextProvider\BacktraceContextProvider;
1516
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
17+
use Symfony\Component\VarDumper\Dumper\VarDumperOptions;
1618

1719
/**
1820
* @author Nicolas Grekas <p@tchwork.com>
@@ -275,12 +277,17 @@ public function dump(DumperInterface $dumper)
275277
$cursor->hashType = -1;
276278
$cursor->attr = $this->context[SourceContextProvider::class] ?? [];
277279
$label = $this->context['label'] ?? '';
280+
$options = $this->context['options'] ?? new VarDumperOptions();
278281

279282
if ($cursor->attr || '' !== $label) {
280283
$dumper->dumpScalar($cursor, 'label', $label);
281284
}
282285
$cursor->hashType = 0;
283286
$this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
287+
288+
if (false !== $options->get(VarDumperOptions::TRACE) && $cursor->attr = $this->context[BacktraceContextProvider::class] ?? []) {
289+
$this->dumpDebugBacktrace($dumper, $cursor);
290+
}
284291
}
285292

286293
/**
@@ -431,4 +438,14 @@ private function getStub(mixed $item): mixed
431438

432439
return $stub;
433440
}
441+
442+
private function dumpDebugBacktrace(DumperInterface $dumper, Cursor $cursor): void
443+
{
444+
$backtrace = $cursor->attr['backtrace'];
445+
446+
$dumper->dumpScalar($cursor, 'default', '');
447+
$dumper->dumpScalar($cursor, 'default', '**DEBUG BACKTRACE**');
448+
449+
$backtrace->dump($dumper);
450+
}
434451
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\ContextProvider;
13+
14+
use Symfony\Component\VarDumper\Caster\TraceStub;
15+
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
16+
use Symfony\Component\VarDumper\Cloner\VarCloner;
17+
use Symfony\Component\VarDumper\Dumper\VarDumperOptions;
18+
19+
/**
20+
* Provides the debug stacktrace of the VarDumper call.
21+
*
22+
* @author Alexandre Daubois <alex.daubois@gmail.com>
23+
*/
24+
final class BacktraceContextProvider implements ContextProviderInterface
25+
{
26+
private const BACKTRACE_CONTEXT_PROVIDER_DEPTH = 4;
27+
28+
public function __construct(
29+
private readonly bool|int $limit,
30+
private ?ClonerInterface $cloner
31+
) {
32+
$this->cloner ??= new VarCloner();
33+
}
34+
35+
public function getContext(): ?array
36+
{
37+
if (false === $this->limit) {
38+
return [];
39+
}
40+
41+
$context = [];
42+
$traces = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
43+
44+
for ($i = self::BACKTRACE_CONTEXT_PROVIDER_DEPTH; $i < \count($traces); ++$i) {
45+
if (VarDumperOptions::class === ($traces[$i + 1]['class'] ?? null)) {
46+
continue;
47+
}
48+
49+
$context[] = $traces[$i];
50+
51+
if ($this->limit === \count($context)) {
52+
break;
53+
}
54+
}
55+
56+
$stub = new TraceStub($context);
57+
58+
return ['backtrace' => $this->cloner->cloneVar($stub->value)];
59+
}
60+
}
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Caster\ScalarStub;
15+
16+
/**
17+
* @author Alexandre Daubois <alex.daubois@gmail.com>
18+
*/
19+
class VarDumperOptions
20+
{
21+
public const FORMAT = '_format';
22+
public const TRACE = '_trace';
23+
public const MAX_ITEMS = '_max_items';
24+
public const MIN_DEPTH = '_min_depth';
25+
public const MAX_STRING = '_max_string';
26+
public const MAX_DEPTH = '_max_depth';
27+
public const MAX_ITEMS_PER_DEPTH = '_max_items_per_depth';
28+
public const THEME = '_theme';
29+
public const FLAGS = '_flags';
30+
public const CHARSET = '_charset';
31+
32+
public const AVAILABLE_OPTIONS = [
33+
self::FORMAT,
34+
self::TRACE,
35+
self::MAX_ITEMS,
36+
self::MIN_DEPTH,
37+
self::MAX_STRING,
38+
self::MAX_DEPTH,
39+
self::MAX_ITEMS_PER_DEPTH,
40+
self::THEME,
41+
self::FLAGS,
42+
self::CHARSET,
43+
];
44+
45+
private array $options;
46+
47+
public function __construct(array $options = [])
48+
{
49+
$this->options = array_filter(
50+
$options,
51+
static fn (mixed $key): bool => \in_array($key, self::AVAILABLE_OPTIONS),
52+
\ARRAY_FILTER_USE_KEY
53+
);
54+
}
55+
56+
/**
57+
* @template T
58+
*
59+
* @param T ...$vars
60+
*
61+
* @return T
62+
*/
63+
public function dump(mixed ...$vars): mixed
64+
{
65+
if (!$vars) {
66+
$vars = [new ScalarStub('🐛')];
67+
}
68+
69+
return dump(...$vars + $this->options);
70+
}
71+
72+
public function dd(mixed ...$vars): never
73+
{
74+
dd(...$vars + $this->options);
75+
}
76+
77+
public function format(?string $format): static
78+
{
79+
$this->options[self::FORMAT] = $format;
80+
81+
return $this;
82+
}
83+
84+
public function trace(bool|int $trace = true): static
85+
{
86+
$this->options[self::TRACE] = $trace;
87+
88+
return $this;
89+
}
90+
91+
public function maxItems(int $maxItems): static
92+
{
93+
$this->options[self::MAX_ITEMS] = $maxItems;
94+
95+
return $this;
96+
}
97+
98+
public function minDepth(int $minDepth): static
99+
{
100+
$this->options[self::MIN_DEPTH] = $minDepth;
101+
102+
return $this;
103+
}
104+
105+
public function maxString(int $maxString): static
106+
{
107+
$this->options[self::MAX_STRING] = $maxString;
108+
109+
return $this;
110+
}
111+
112+
public function maxDepth(int $maxDepth): static
113+
{
114+
$this->options[self::MAX_DEPTH] = $maxDepth;
115+
116+
return $this;
117+
}
118+
119+
public function maxItemsPerDepth(int $maxItemsPerDepth): static
120+
{
121+
$this->options[self::MAX_ITEMS_PER_DEPTH] = $maxItemsPerDepth;
122+
123+
return $this;
124+
}
125+
126+
public function theme(?string $theme): static
127+
{
128+
$this->options[self::THEME] = $theme ?? 'dark';
129+
130+
return $this;
131+
}
132+
133+
/**
134+
* @param AbstractDumper::DUMP_* $flags
135+
*/
136+
public function flags(int $flags): static
137+
{
138+
$this->options[self::FLAGS] = $flags;
139+
140+
return $this;
141+
}
142+
143+
/**
144+
* Display arrays with short form (omitting elements count and `array` prefix).
145+
*/
146+
public function showLightArray(): static
147+
{
148+
$this->options[self::FLAGS] = ($this->options[self::FLAGS] ?? 0) | AbstractDumper::DUMP_LIGHT_ARRAY;
149+
150+
return $this;
151+
}
152+
153+
/**
154+
* Display string length, just before its value.
155+
*/
156+
public function showStringLength(): static
157+
{
158+
$this->options[self::FLAGS] = ($this->options[self::FLAGS] ?? 0) | AbstractDumper::DUMP_STRING_LENGTH;
159+
160+
return $this;
161+
}
162+
163+
/**
164+
* Display a comma at the end of the line of an array element.
165+
*/
166+
public function showCommaSeparator(): static
167+
{
168+
$this->options[self::FLAGS] = ($this->options[self::FLAGS] ?? 0) | AbstractDumper::DUMP_COMMA_SEPARATOR;
169+
170+
return $this;
171+
}
172+
173+
/**
174+
* Display a trailing comma after the last element of an array.
175+
*/
176+
public function showTrailingComma(): static
177+
{
178+
$this->options[self::FLAGS] = ($this->options[self::FLAGS] ?? 0) | AbstractDumper::DUMP_TRAILING_COMMA;
179+
180+
return $this;
181+
}
182+
183+
public function charset(string $charset): static
184+
{
185+
$this->options[self::CHARSET] = $charset;
186+
187+
return $this;
188+
}
189+
190+
public function get(string $option): mixed
191+
{
192+
return $this->options[$option] ?? null;
193+
}
194+
195+
public function toArray(): array
196+
{
197+
return $this->options;
198+
}
199+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy