Skip to content

Commit

Permalink
feature #48432 [VarDumper] Add support of named arguments to dd() a…
Browse files Browse the repository at this point in the history
…nd `dump()` to display a label (alexandre-daubois)

This PR was merged into the 6.3 branch.

Discussion
----------

[VarDumper] Add support of named arguments to `dd()` and `dump()` to display a label

| Q             | A
| ------------- | ---
| Branch?       | 6.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | _N/A_
| License       | MIT
| Doc PR        | _Todo_

Following an idea from `@nicolas`-grekas, the goal here is to ease debugging with `dd()` and `dump()` by supporting named arguments passed to them. This will display a label, helping understand the goal/meaning of a dump.

**Example in web browser:**

![image](https://user-images.githubusercontent.com/2144837/205279233-7c250d07-4616-4ed8-907e-b1b3cac9a3f2.png)

**Example in CLI:**

![image](https://user-images.githubusercontent.com/2144837/205122796-79427c98-48fe-4f11-b2c5-58b51a2fbbf6.png)

The above example is clickable and points to `file:///home/alexandredaubois/PhpstormProjects/dummy_project/src/Command/TestCommand.php#L15`.

No more `dd("First one", $var1, "Second var", $var2);`!

Commits
-------

2519c5c830 [VarDumper] Add support of named arguments to `dd()` and `dump()` to display the argument name
  • Loading branch information
nicolas-grekas committed Dec 15, 2022
2 parents f0419c3 + 0d0fa05 commit ca4660e
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ CHANGELOG
---

* Add caster for `WeakMap`
* Add support of named arguments to `dd()` and `dump()` to display the argument name

6.2
---
Expand Down
27 changes: 27 additions & 0 deletions Caster/ScalarStub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\VarDumper\Caster;

use Symfony\Component\VarDumper\Cloner\Stub;

/**
* Represents any arbitrary value.
*
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
class ScalarStub extends Stub
{
public function __construct(mixed $value)
{
$this->value = $value;
}
}
8 changes: 8 additions & 0 deletions Caster/StubCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,12 @@ public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNeste

return $a;
}

public static function castScalar(ScalarStub $scalarStub, array $a, Stub $stub)
{
$stub->type = Stub::TYPE_SCALAR;
$stub->attr['value'] = $scalarStub->value;

return $a;
}
}
1 change: 1 addition & 0 deletions Cloner/AbstractCloner.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ abstract class AbstractCloner implements ClonerInterface
'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'],
'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'],
'Symfony\Component\VarDumper\Caster\ScalarStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castScalar'],

'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'],

Expand Down
12 changes: 11 additions & 1 deletion Cloner/Data.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,11 @@ public function withContext(array $context): static
return $data;
}

public function getContext(): array
{
return $this->context;
}

/**
* Seeks to a specific key in nested data structures.
*/
Expand Down Expand Up @@ -262,11 +267,12 @@ public function dump(DumperInterface $dumper)
{
$refs = [0];
$cursor = new Cursor();
$label = $this->context['label'] ?? '';

if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
$cursor->attr['if_links'] = true;
$cursor->hashType = -1;
$dumper->dumpScalar($cursor, 'default', '^');
$dumper->dumpScalar($cursor, 'default', $label.'^');
$cursor->attr = ['if_links' => true];
$dumper->dumpScalar($cursor, 'default', ' ');
$cursor->hashType = 0;
Expand Down Expand Up @@ -362,6 +368,10 @@ private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs,
$dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
break;

case Stub::TYPE_SCALAR:
$dumper->dumpScalar($cursor, 'default', $item->attr['value']);
break;

default:
throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type));
}
Expand Down
1 change: 1 addition & 0 deletions Cloner/Stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Stub
public const TYPE_ARRAY = 3;
public const TYPE_OBJECT = 4;
public const TYPE_RESOURCE = 5;
public const TYPE_SCALAR = 6;

public const STRING_BINARY = 1;
public const STRING_UTF8 = 2;
Expand Down
2 changes: 1 addition & 1 deletion Dumper/ContextualizedDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __construct(DataDumperInterface $wrappedDumper, array $contextPr

public function dump(Data $data)
{
$context = [];
$context = $data->getContext();
foreach ($this->contextProviders as $contextProvider) {
$context[$contextProvider::class] = $contextProvider->getContext();
}
Expand Down
33 changes: 24 additions & 9 deletions Resources/functions/dump.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,36 @@
* file that was distributed with this source code.
*/

use Symfony\Component\VarDumper\Caster\ScalarStub;
use Symfony\Component\VarDumper\VarDumper;

if (!function_exists('dump')) {
/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Alexandre Daubois <alex.daubois@gmail.com>
*/
function dump(mixed $var, mixed ...$moreVars): mixed
function dump(mixed ...$vars): mixed
{
VarDumper::dump($var);
if (!$vars) {
VarDumper::dump(new ScalarStub('🐛'));

foreach ($moreVars as $v) {
VarDumper::dump($v);
return null;
}

if (1 < func_num_args()) {
return func_get_args();
if (isset($vars[0]) && 1 === count($vars)) {
VarDumper::dump($vars[0]);
$k = 0;
} else {
foreach ($vars as $k => $v) {
VarDumper::dump($v, is_int($k) ? 1 + $k : $k);
}
}

return $var;
if (1 < count($vars)) {
return $vars;
}

return $vars[$k];
}
}

Expand All @@ -38,8 +49,12 @@ function dd(mixed ...$vars): never
header('HTTP/1.1 500 Internal Server Error');
}

foreach ($vars as $v) {
VarDumper::dump($v);
if (isset($vars[0]) && 1 === count($vars)) {
VarDumper::dump($vars[0]);
} else {
foreach ($vars as $k => $v) {
VarDumper::dump($v, is_int($k) ? 1 + $k : $k);
}
}

exit(1);
Expand Down
16 changes: 15 additions & 1 deletion Tests/Caster/StubCasterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\VarDumper\Caster\ArgsStub;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Component\VarDumper\Caster\LinkStub;
use Symfony\Component\VarDumper\Caster\ScalarStub;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
Expand Down Expand Up @@ -87,6 +88,19 @@ public function testArgsStubWithClosure()
$this->assertDumpMatchesFormat($expectedDump, $args);
}

public function testEmptyStub()
{
$args = [new ScalarStub('🐛')];

$expectedDump = <<<'EODUMP'
array:1 [
0 => 🐛
]
EODUMP;

$this->assertDumpMatchesFormat($expectedDump, $args);
}

public function testLinkStub()
{
$var = [new LinkStub(__CLASS__, 0, __FILE__)];
Expand Down Expand Up @@ -203,7 +217,7 @@ public function testClassStubWithAnonymousClass()

$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp data-depth=1 class=sf-dump-expanded>
<span class=sf-dump-index>0</span> => "<a href="%sStubCasterTest.php:195" rel="noopener noreferrer"><span class=sf-dump-str title="19 characters">Exception@anonymous</span></a>"
<span class=sf-dump-index>0</span> => "<a href="%sStubCasterTest.php:209" rel="noopener noreferrer"><span class=sf-dump-str title="19 characters">Exception@anonymous</span></a>"
</samp>]
</bar>
EODUMP;
Expand Down
43 changes: 41 additions & 2 deletions Tests/Dumper/FunctionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@

class FunctionsTest extends TestCase
{
public function testDumpWithoutArg()
{
$this->setupVarDumper();

ob_start();
$return = dump();
ob_end_clean();

$this->assertNull($return);
}

public function testDumpReturnsFirstArg()
{
$this->setupVarDumper();
Expand All @@ -28,7 +39,20 @@ public function testDumpReturnsFirstArg()
$return = dump($var1);
ob_end_clean();

$this->assertEquals($var1, $return);
$this->assertSame($var1, $return);
}

public function testDumpReturnsFirstNamedArgWithoutSectionName()
{
$this->setupVarDumper();

$var1 = 'a';

ob_start();
$return = dump(first: $var1);
ob_end_clean();

$this->assertSame($var1, $return);
}

public function testDumpReturnsAllArgsInArray()
Expand All @@ -43,7 +67,22 @@ public function testDumpReturnsAllArgsInArray()
$return = dump($var1, $var2, $var3);
ob_end_clean();

$this->assertEquals([$var1, $var2, $var3], $return);
$this->assertSame([$var1, $var2, $var3], $return);
}

public function testDumpReturnsAllNamedArgsInArray()
{
$this->setupVarDumper();

$var1 = 'a';
$var2 = 'b';
$var3 = 'c';

ob_start();
$return = dump($var1, second: $var2, third: $var3);
ob_end_clean();

$this->assertSame([$var1, 'second' => $var2, 'third' => $var3], $return);
}

protected function setupVarDumper()
Expand Down
18 changes: 14 additions & 4 deletions VarDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,17 @@ class VarDumper
*/
private static $handler;

public static function dump(mixed $var)
/**
* @param string|null $label
*/
public static function dump(mixed $var/* , string $label = null */)
{
$label = 2 <= \func_num_args() ? func_get_arg(1) : null;
if (null === self::$handler) {
self::register();
}

return (self::$handler)($var);
return (self::$handler)($var, $label);
}

public static function setHandler(callable $callable = null): ?callable
Expand Down Expand Up @@ -90,8 +94,14 @@ private static function register(): void
$dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]);
}

self::$handler = function ($var) use ($cloner, $dumper) {
$dumper->dump($cloner->cloneVar($var));
self::$handler = function ($var, string $label = null) use ($cloner, $dumper) {
$var = $cloner->cloneVar($var);

if (null !== $label) {
$var = $var->withContext(['label' => $label]);
}

$dumper->dump($var);
};
}

Expand Down

0 comments on commit ca4660e

Please sign in to comment.