Skip to content

Commit

Permalink
bug #50960 [VarDumper] Fix dumping ArrayObject with `DumpDataCollec…
Browse files Browse the repository at this point in the history
…tor` (lyrixx, HypeMC)

This PR was merged into the 5.4 branch.

Discussion
----------

[VarDumper] Fix dumping `ArrayObject` with `DumpDataCollector`

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #50940
| License       | MIT
| Doc PR        | -

The main problem here is that the `ArrayObjectstorage` key in [the array returned by `__debugInfo()`](https://github.com/symfony/symfony/blob/de7ab4d85dcc94032b77f1a15d7a030714a1f734/src/Symfony/Component/VarDumper/Caster/SplCaster.php#L229-L229) seems to be a reference: https://3v4l.org/8rSFn (a bug in PHP perhaps?)

Since the `DumpDataCollector` does the actual dumping in the `__destructor()` the `ArrayObjectstorage` is modified by then which messes with the object created by the `VarCloner`.

Commits
-------

b25f377 [VarDumper] Fix dumping `ArrayObject` with `DumpDataCollector`
1f2c6f7 [VarDumper] Add tests to demonstrate a bug when dumping ArrayObject with full stack fmk
  • Loading branch information
nicolas-grekas committed Jul 13, 2023
2 parents a056e7b + b25f377 commit 23da9db
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 12 deletions.
7 changes: 4 additions & 3 deletions src/Symfony/Component/VarDumper/Caster/SplCaster.php
Expand Up @@ -229,10 +229,11 @@ private static function castSplArray($c, array $a, Stub $stub, bool $isNested):
$a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
$c->setFlags($flags);
}
if (\PHP_VERSION_ID < 70400) {
$a[$prefix.'storage'] = $c->getArrayCopy();
}

unset($a["\0ArrayObject\0storage"], $a["\0ArrayIterator\0storage"]);

$a += [
$prefix.'storage' => $c->getArrayCopy(),
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
];
Expand Down
Expand Up @@ -44,7 +44,7 @@ public function getContext(): ?array

$file = $trace[1]['file'];
$line = $trace[1]['line'];
$name = false;
$name = '-' === $file || 'Standard input code' === $file ? 'Standard input code' : false;
$fileExcerpt = false;

for ($i = 2; $i < $this->limit; ++$i) {
Expand Down
10 changes: 2 additions & 8 deletions src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php
Expand Up @@ -174,17 +174,14 @@ class([123]) extends \ArrayObject {};
$expected = <<<EOTXT
ArrayObject@anonymous {
+"foo": 234
-storage: array:1 [
storage: array:1 [
0 => 123
]
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
iteratorClass: "ArrayIterator"
}
EOTXT;
if (\PHP_VERSION_ID < 70400) {
$expected = str_replace('-storage:', 'storage:', $expected);
}
$this->assertDumpEquals($expected, $var);
}

Expand All @@ -195,16 +192,13 @@ public function testArrayIterator()
$expected = <<<EOTXT
Symfony\Component\VarDumper\Tests\Caster\MyArrayIterator {
-foo: 123
-storage: array:1 [
storage: array:1 [
0 => 234
]
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
}
EOTXT;
if (\PHP_VERSION_ID < 70400) {
$expected = str_replace('-storage:', 'storage:', $expected);
}
$this->assertDumpEquals($expected, $var);
}

Expand Down
@@ -0,0 +1,69 @@
--TEST--
Test integration with Symfony's DumpDataCollector
--FILE--
<?php
putenv('NO_COLOR=1');

$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
}
require $vendor.'/vendor/autoload.php';

use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\VarDumper;

VarDumper::setHandler(function ($var, string $label = null) {
$dumper = new DumpDataCollector();
$cloner = new VarCloner();
$handler = function ($var, string $label = null) use ($dumper, $cloner) {
$var = $cloner->cloneVar($var);
if (null !== $label) {
$var = $var->withContext(['label' => $label]);
}

$dumper->dump($var);
};
VarDumper::setHandler($handler);
$handler($var, $label);
});

$arrayObject = new \ArrayObject();
dump($arrayObject);
$arrayObject['X'] = 'A';
$arrayObject['Y'] = new \ArrayObject(['type' => 'object']);
$arrayObject['Y']['Z'] = 'B';

$arrayIterator = new \ArrayIterator();
dump($arrayIterator);
$arrayIterator['X'] = 'A';
$arrayIterator['Y'] = new \ArrayIterator(['type' => 'object']);
$arrayIterator['Y']['Z'] = 'B';

$recursiveArrayIterator = new \RecursiveArrayIterator();
dump($recursiveArrayIterator);
$recursiveArrayIterator['X'] = 'A';
$recursiveArrayIterator['Y'] = new \RecursiveArrayIterator(['type' => 'object']);
$recursiveArrayIterator['Y']['Z'] = 'B';

--EXPECTF--
%s on line %d:
ArrayObject {#%d
storage: []
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
iteratorClass: "ArrayIterator"
}
%s on line %d:
ArrayIterator {#%d
storage: []
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
}
%s on line %d:
RecursiveArrayIterator {#%d
storage: []
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
}
1 change: 1 addition & 0 deletions src/Symfony/Component/VarDumper/composer.json
Expand Up @@ -23,6 +23,7 @@
"require-dev": {
"ext-iconv": "*",
"symfony/console": "^4.4|^5.0|^6.0",
"symfony/http-kernel": "^4.4|^5.0|^6.0",
"symfony/process": "^4.4|^5.0|^6.0",
"symfony/uid": "^5.1|^6.0",
"twig/twig": "^2.13|^3.0.4"
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/VarDumper/phpunit.xml.dist
Expand Up @@ -17,6 +17,7 @@
<testsuites>
<testsuite name="Symfony VarDumper Component Test Suite">
<directory>./Tests/</directory>
<directory suffix=".phpt">./Tests/Dumper/functions/</directory>
</testsuite>
</testsuites>

Expand Down

0 comments on commit 23da9db

Please sign in to comment.