From e26dc2c9587fafc06eb99ffc35ee9f3172193c99 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 8 Jan 2015 11:41:30 +0100 Subject: [PATCH] [VarDumper] fix very special vars handling --- .../DataCollector/DumpDataCollectorTest.php | 2 +- .../VarDumper/Cloner/AbstractCloner.php | 2 + .../Component/VarDumper/Cloner/Data.php | 2 +- .../Component/VarDumper/Cloner/VarCloner.php | 14 +- .../VarDumper/Tests/CliDumperTest.php | 147 +++++++++++++++++- 5 files changed, 163 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php index 5c8fdb6ed1..b3209c213b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -50,7 +50,7 @@ class DumpDataCollectorTest extends \PHPUnit_Framework_TestCase $this->assertSame($xDump, $dump); $this->assertStringStartsWith( - 'a:1:{i:0;a:5:{s:4:"data";O:39:"Symfony\Component\VarDumper\Cloner\Data":4:{s:45:"Symfony\Component\VarDumper\Cloner\Datadata";a:1:{i:0;a:1:{i:0;i:123;}}s:49:"Symfony\Component\VarDumper\Cloner\DatamaxDepth";i:-1;s:57:"Symfony\Component\VarDumper\Cloner\DatamaxItemsPerDepth";i:-1;s:54:"Symfony\Component\VarDumper\Cloner\DatauseRefHandles";i:-1;}s:4:"name";s:25:"DumpDataCollectorTest.php";s:4:"file";s:', + 'a:1:{i:0;a:5:{s:4:"data";O:39:"Symfony\Component\VarDumper\Cloner\Data":4:{s:45:"Symfony\Component\VarDumper\Cloner\Datadata";a:1:{i:0;a:1:{i:0;i:123;}}s:49:"Symfony\Component\VarDumper\Cloner\DatamaxDepth";i:20;s:57:"Symfony\Component\VarDumper\Cloner\DatamaxItemsPerDepth";i:-1;s:54:"Symfony\Component\VarDumper\Cloner\DatauseRefHandles";i:-1;}s:4:"name";s:25:"DumpDataCollectorTest.php";s:4:"file";s:', str_replace("\0", '', $collector->serialize()) ); diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 827c4c7370..49476d5bec 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -82,6 +82,7 @@ abstract class AbstractCloner implements ClonerInterface protected $maxItems = 2500; protected $maxString = -1; + protected $useExt; private $casters = array(); private $prevErrorHandler; @@ -98,6 +99,7 @@ abstract class AbstractCloner implements ClonerInterface $casters = static::$defaultCasters; } $this->addCasters($casters); + $this->useExt = extension_loaded('symfony_debug'); } /** diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 9f970a4c4d..6ef69045e5 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -17,7 +17,7 @@ namespace Symfony\Component\VarDumper\Cloner; class Data { private $data; - private $maxDepth = -1; + private $maxDepth = 20; private $maxItemsPerDepth = -1; private $useRefHandles = -1; diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 605977be80..1b625d5fda 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -24,7 +24,7 @@ class VarCloner extends AbstractCloner */ protected function doClone($var) { - $useExt = extension_loaded('symfony_debug'); + $useExt = $this->useExt; $i = 0; // Current iteration position in $queue $len = 1; // Length of $queue $pos = 0; // Number of cloned items past the first level @@ -120,7 +120,19 @@ class VarCloner extends AbstractCloner $stub->type = Stub::TYPE_ARRAY; $stub->class = Stub::ARRAY_ASSOC; $stub->value = $zval['array_count'] ?: count($v); + $a = $v; + $a[] = null; + $h = count($v); + array_pop($a); + + // Happens with copies of $GLOBALS + if ($h !== $stub->value) { + $a = array(); + foreach ($v as $gk => &$gv) { + $a[$gk] =& $gv; + } + } } break; diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index 49710aaa88..d67c7ab1e3 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -104,8 +104,153 @@ array:25 [ EOTXT , - $out ); } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testSpecialVars56() + { + if (PHP_VERSION_ID < 50600) { + $this->markTestSkipped('PHP 5.6 is required'); + } + + $var = $this->getSpecialVars(); + + $dumper = new CliDumper(); + $dumper->setColors(false); + $cloner = new VarCloner(); + + $data = $cloner->cloneVar($var); + $out = fopen('php://memory', 'r+b'); + $dumper->dump($data, $out); + rewind($out); + $out = stream_get_contents($out); + + $this->assertSame( + << array:1 [ + 0 => &1 array:1 [ + 0 => &1 array:1 [&1] + ] + ] + 1 => array:1 [ + "GLOBALS" => &2 array:1 [ + "GLOBALS" => &2 array:1 [&2] + ] + ] +] + +EOTXT + , + $out + ); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testGlobalsNoExt() + { + $var = $this->getSpecialVars(); + unset($var[0]); + $out = ''; + + $dumper = new CliDumper(function ($line, $depth) use (&$out) { + if ($depth >= 0) { + $out .= str_repeat(' ', $depth).$line."\n"; + } + }); + $dumper->setColors(false); + $cloner = new VarCloner(); + + $refl = new \ReflectionProperty($cloner, 'useExt'); + $refl->setAccessible(true); + $refl->setValue($cloner, false); + + $data = $cloner->cloneVar($var); + $dumper->dump($data); + + $this->assertSame( + << array:1 [ + "GLOBALS" => &1 array:1 [ + "GLOBALS" => &1 array:1 [&1] + ] + ] + 2 => &1 array:1 [&1] +] + +EOTXT + , + $out + ); + } + + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testBuggyRefs() + { + if (PHP_VERSION_ID >= 50600) { + $this->markTestSkipped('PHP 5.6 fixed refs counting'); + } + + $var = $this->getSpecialVars(); + $var = $var[0]; + + $dumper = new CliDumper(); + $dumper->setColors(false); + $cloner = new VarCloner(); + + $data = $cloner->cloneVar($var)->getLimitedClone(3, -1); + $out = ''; + $dumper->dump($data, function ($line, $depth) use (&$out) { + if ($depth >= 0) { + $out .= str_repeat(' ', $depth).$line."\n"; + } + }); + + $this->assertSame( + << array:1 [ + 0 => array:1 [ + 0 => array:1 [ + …1 + ] + ] + ] +] + +EOTXT + , + $out + ); + } + + private function getSpecialVars() + { + foreach (array_keys($GLOBALS) as $var) { + if ('GLOBALS' !== $var) { + unset($GLOBALS[$var]); + } + } + + $var = function &() { + $var = array(); + $var[] =& $var; + + return $var; + }; + + return array($var(), $GLOBALS, &$GLOBALS); + } }