diff --git a/.travis.yml b/.travis.yml index b5d935658c..0626897960 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,15 +24,12 @@ env: - SYMFONY_DEPRECATIONS_HELPER=weak before_install: - - if [[ "$TRAVIS_PULL_REQUEST" != "false" ]]; then git fetch origin "refs/pull/$TRAVIS_PULL_REQUEST/merge"; else git fetch origin "$TRAVIS_BRANCH"; fi; - - if [[ "$TRAVIS_COMMIT" != `git rev-parse FETCH_HEAD` ]]; then echo "Pull request or branch commit hash has changed, aborting!"; exit 1; fi; - travis_retry sudo apt-get install parallel - composer self-update - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then phpenv config-rm xdebug.ini; fi; - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]] && [ $(php -r "echo PHP_MINOR_VERSION;") -le 4 ]; then echo "extension = apc.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; - - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then pecl install -f memcached-2.1.0; fi; - - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini; fi; + - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then (pecl install -f memcached-2.1.0 && echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini) || echo "Let's continue without memcache extension"; fi; - if [[ "$TRAVIS_PHP_VERSION" != *"nightly" ]]; then php -i; fi; - sudo locale-gen fr_FR.UTF-8 && sudo update-locale # Set the COMPOSER_ROOT_VERSION to the right version according to the branch being built diff --git a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php index 08ee18859b..4e9b351c18 100644 --- a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php @@ -46,7 +46,7 @@ class AmqpCaster public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested) { - $prefix = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; // BC layer in the ampq lib if (method_exists($c, 'getReadTimeout')) { @@ -70,7 +70,7 @@ class AmqpCaster public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested) { - $prefix = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; $a += array( $prefix.'isConnected' => $c->isConnected(), @@ -85,7 +85,7 @@ class AmqpCaster public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested) { - $prefix = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; $a += array( $prefix.'name' => $c->getName(), @@ -100,7 +100,7 @@ class AmqpCaster public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested) { - $prefix = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; $a += array( $prefix.'name' => $c->getName(), @@ -114,12 +114,15 @@ class AmqpCaster return $a; } - public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested) + public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0) { - $prefix = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += array($prefix.'body' => $c->getBody()); + } $a += array( - $prefix.'body' => $c->getBody(), $prefix.'routingKey' => $c->getRoutingKey(), $prefix.'deliveryTag' => $c->getDeliveryTag(), $prefix.'deliveryMode' => new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()), diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index 716d9ce9f8..4ce8cf8a12 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -29,6 +29,39 @@ class Caster const EXCLUDE_NOT_IMPORTANT = 256; const EXCLUDE_STRICT = 512; + const PREFIX_VIRTUAL = "\0~\0"; + const PREFIX_DYNAMIC = "\0+\0"; + const PREFIX_PROTECTED = "\0*\0"; + + /** + * Casts objects to arrays and adds the dynamic property prefix. + * + * @param object $obj The object to cast. + * @param ReflectionClass $reflector The class reflector to use for inspecting the object definition. + * + * @return array The array-cast of the object, with prefixed dynamic properties. + */ + public static function castObject($obj, \ReflectionClass $reflector) + { + if ($reflector->hasMethod('__debugInfo')) { + $a = $obj->__debugInfo(); + } else { + $a = (array) $obj; + } + + if ($a) { + $p = array_keys($a); + foreach ($p as $i => $k) { + if (!isset($k[0]) || ("\0" !== $k[0] && !$reflector->hasProperty($k))) { + $p[$i] = self::PREFIX_DYNAMIC.$k; + } + } + $a = array_combine($p, $a); + } + + return $a; + } + /** * Filters out the specified properties. * diff --git a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php index d5b3c87a73..e04cf9534b 100644 --- a/src/Symfony/Component/VarDumper/Caster/DOMCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DOMCaster.php @@ -63,8 +63,9 @@ class DOMCaster public static function castException(\DOMException $e, array $a, Stub $stub, $isNested) { - if (isset($a["\0*\0code"], self::$errorCodes[$a["\0*\0code"]])) { - $a["\0*\0code"] = new ConstStub(self::$errorCodes[$a["\0*\0code"]], $a["\0*\0code"]); + $k = Caster::PREFIX_PROTECTED.'code'; + if (isset($a[$k], self::$errorCodes[$a[$k]])) { + $a[$k] = new ConstStub(self::$errorCodes[$a[$k]], $a[$k]); } return $a; @@ -82,8 +83,8 @@ class DOMCaster public static function castImplementation($dom, array $a, Stub $stub, $isNested) { $a += array( - "\0~\0Core" => '1.0', - "\0~\0XML" => '2.0', + Caster::PREFIX_VIRTUAL.'Core' => '1.0', + Caster::PREFIX_VIRTUAL.'XML' => '2.0', ); return $a; @@ -129,11 +130,8 @@ class DOMCaster return $a; } - public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested) + public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0) { - $formatOutput = $dom->formatOutput; - $dom->formatOutput = true; - $a += array( 'doctype' => $dom->doctype, 'implementation' => $dom->implementation, @@ -148,16 +146,20 @@ class DOMCaster 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI, 'config' => $dom->config, - 'formatOutput' => $formatOutput, + 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, 'preserveWhiteSpace' => $dom->preserveWhiteSpace, 'recover' => $dom->recover, 'substituteEntities' => $dom->substituteEntities, - "\0~\0xml" => $dom->saveXML(), ); - $dom->formatOutput = $formatOutput; + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += array(Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()); + $dom->formatOutput = $formatOutput; + } return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/MongoCaster.php b/src/Symfony/Component/VarDumper/Caster/MongoCaster.php index 19dba96e4e..92258f06fa 100644 --- a/src/Symfony/Component/VarDumper/Caster/MongoCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/MongoCaster.php @@ -22,14 +22,12 @@ class MongoCaster { public static function castCursor(\MongoCursorInterface $cursor, array $a, Stub $stub, $isNested) { - $prefix = "\0~\0"; - if ($info = $cursor->info()) { foreach ($info as $k => $v) { - $a[$prefix.$k] = $v; + $a[Caster::PREFIX_VIRTUAL.$k] = $v; } } - $a[$prefix.'dead'] = $cursor->dead(); + $a[Caster::PREFIX_VIRTUAL.'dead'] = $cursor->dead(); return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/PdoCaster.php b/src/Symfony/Component/VarDumper/Caster/PdoCaster.php index 5f99fcd3c7..48c5306985 100644 --- a/src/Symfony/Component/VarDumper/Caster/PdoCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/PdoCaster.php @@ -78,21 +78,21 @@ class PdoCaster } } - $m = "\0~\0"; + $prefix = Caster::PREFIX_VIRTUAL; $a += array( - $m.'inTransaction' => method_exists($c, 'inTransaction'), - $m.'errorInfo' => $c->errorInfo(), - $m.'attributes' => $attr, + $prefix.'inTransaction' => method_exists($c, 'inTransaction'), + $prefix.'errorInfo' => $c->errorInfo(), + $prefix.'attributes' => $attr, ); - if ($a[$m.'inTransaction']) { - $a[$m.'inTransaction'] = $c->inTransaction(); + if ($a[$prefix.'inTransaction']) { + $a[$prefix.'inTransaction'] = $c->inTransaction(); } else { - unset($a[$m.'inTransaction']); + unset($a[$prefix.'inTransaction']); } - if (!isset($a[$m.'errorInfo'][1], $a[$m.'errorInfo'][2])) { - unset($a[$m.'errorInfo']); + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); } $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode); @@ -102,11 +102,11 @@ class PdoCaster public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested) { - $m = "\0~\0"; - $a[$m.'errorInfo'] = $c->errorInfo(); + $prefix = Caster::PREFIX_VIRTUAL; + $a[$prefix.'errorInfo'] = $c->errorInfo(); - if (!isset($a[$m.'errorInfo'][1], $a[$m.'errorInfo'][2])) { - unset($a[$m.'errorInfo']); + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); } return $a; diff --git a/src/Symfony/Component/VarDumper/Caster/SplCaster.php b/src/Symfony/Component/VarDumper/Caster/SplCaster.php index df8e009c31..79e8bb80b9 100644 --- a/src/Symfony/Component/VarDumper/Caster/SplCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SplCaster.php @@ -22,14 +22,15 @@ class SplCaster { public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested) { + $prefix = Caster::PREFIX_VIRTUAL; $class = $stub->class; $flags = $c->getFlags(); $b = array( - "\0~\0flag::STD_PROP_LIST" => (bool) ($flags & \ArrayObject::STD_PROP_LIST), - "\0~\0flag::ARRAY_AS_PROPS" => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), - "\0~\0iteratorClass" => $c->getIteratorClass(), - "\0~\0storage" => $c->getArrayCopy(), + $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), + $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), + $prefix.'iteratorClass' => $c->getIteratorClass(), + $prefix.'storage' => $c->getArrayCopy(), ); if ($class === 'ArrayObject') { @@ -37,17 +38,7 @@ class SplCaster } else { if (!($flags & \ArrayObject::STD_PROP_LIST)) { $c->setFlags(\ArrayObject::STD_PROP_LIST); - - if ($a = (array) $c) { - $class = new \ReflectionClass($class); - foreach ($a as $k => $p) { - if (!isset($k[0]) || ("\0" !== $k[0] && !$class->hasProperty($k))) { - unset($a[$k]); - $a["\0+\0".$k] = $p; - } - } - } - + $a = Caster::castObject($c, new \ReflectionClass($class)); $c->setFlags($flags); } @@ -60,7 +51,7 @@ class SplCaster public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested) { $a += array( - "\0~\0heap" => iterator_to_array(clone $c), + Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), ); return $a; @@ -68,12 +59,13 @@ class SplCaster public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested) { + $prefix = Caster::PREFIX_VIRTUAL; $mode = $c->getIteratorMode(); $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE); $a += array( - "\0~\0mode" => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_KEEP) ? 'IT_MODE_KEEP' : 'IT_MODE_DELETE'), $mode), - "\0~\0dllist" => iterator_to_array($c), + $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_KEEP) ? 'IT_MODE_KEEP' : 'IT_MODE_DELETE'), $mode), + $prefix.'dllist' => iterator_to_array($c), ); $c->setIteratorMode($mode); @@ -83,7 +75,7 @@ class SplCaster public static function castFixedArray(\SplFixedArray $c, array $a, Stub $stub, $isNested) { $a += array( - "\0~\0storage" => $c->toArray(), + Caster::PREFIX_VIRTUAL.'storage' => $c->toArray(), ); return $a; @@ -92,7 +84,7 @@ class SplCaster public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested) { $storage = array(); - unset($a["\0+\0\0gcdata"]); // Don't hit https://bugs.php.net/65967 + unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 foreach ($c as $obj) { $storage[spl_object_hash($obj)] = array( @@ -102,7 +94,7 @@ class SplCaster } $a += array( - "\0~\0storage" => $storage, + Caster::PREFIX_VIRTUAL.'storage' => $storage, ); return $a; diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 349e7afdff..0ffe20dc1a 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Cloner; +use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Exception\ThrowingCasterException; /** @@ -218,7 +219,6 @@ abstract class AbstractCloner implements ClonerInterface } else { $classInfo = array( $class, - method_exists($class, '__debugInfo'), new \ReflectionClass($class), array_reverse(array('*' => '*', $class => $class) + class_parents($class) + class_implements($class)), ); @@ -226,23 +226,9 @@ abstract class AbstractCloner implements ClonerInterface $this->classInfo[$class] = $classInfo; } - if ($classInfo[1]) { - $a = $this->callCaster(function ($obj) {return $obj->__debugInfo();}, $obj, array(), null, $isNested); - } else { - $a = (array) $obj; - } + $a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[1], null, $isNested); - if ($a) { - $p = array_keys($a); - foreach ($p as $i => $k) { - if (!isset($k[0]) || ("\0" !== $k[0] && !$classInfo[2]->hasProperty($k))) { - $p[$i] = "\0+\0".$k; - } - } - $a = array_combine($p, $a); - } - - foreach ($classInfo[3] as $p) { + foreach ($classInfo[2] as $p) { if (!empty($this->casters[$p = strtolower($p)])) { foreach ($this->casters[$p] as $p) { $a = $this->callCaster($p, $obj, $a, $stub, $isNested); @@ -296,7 +282,7 @@ abstract class AbstractCloner implements ClonerInterface $a = $cast; } } catch (\Exception $e) { - $a[(Stub::TYPE_OBJECT === $stub->type ? "\0~\0" : '').'⚠'] = new ThrowingCasterException($callback, $e); + $a[(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠'] = new ThrowingCasterException($callback, $e); } return $a; diff --git a/src/Symfony/Component/VarDumper/Test/VarDumperTestCase.php b/src/Symfony/Component/VarDumper/Test/VarDumperTestCase.php index 42a915e8ed..006c1dc7a8 100644 --- a/src/Symfony/Component/VarDumper/Test/VarDumperTestCase.php +++ b/src/Symfony/Component/VarDumper/Test/VarDumperTestCase.php @@ -21,12 +21,12 @@ abstract class VarDumperTestCase extends \PHPUnit_Framework_TestCase { public function assertDumpEquals($dump, $data, $message = '') { - $this->assertSame($dump, $this->getVarDumperDump($data), $message); + $this->assertSame(rtrim($dump), $this->getVarDumperDump($data), $message); } public function assertDumpMatchesFormat($dump, $data, $message = '') { - $this->assertStringMatchesFormat($dump, $this->getVarDumperDump($data), $message); + $this->assertStringMatchesFormat(rtrim($dump), $this->getVarDumperDump($data), $message); } private function getVarDumperDump($data) @@ -36,10 +36,9 @@ abstract class VarDumperTestCase extends \PHPUnit_Framework_TestCase $dumper = new CliDumper($h); $dumper->setColors(false); $dumper->dump($cloner->cloneVar($data)->withRefHandles(false)); - fseek($h, 0); - $data = stream_get_contents($h); + $data = stream_get_contents($h, -1, 0); fclose($h); - return $data; + return rtrim($data); } } diff --git a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php index 130447bcf6..0d1489ab44 100644 --- a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php +++ b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php @@ -21,12 +21,12 @@ trait VarDumperTestTrait { public function assertDumpEquals($dump, $data, $message = '') { - $this->assertSame($dump, $this->getVarDumperDump($data), $message); + $this->assertSame(rtrim($dump), $this->getVarDumperDump($data), $message); } public function assertDumpMatchesFormat($dump, $data, $message = '') { - $this->assertStringMatchesFormat($dump, $this->getVarDumperDump($data), $message); + $this->assertStringMatchesFormat(rtrim($dump), $this->getVarDumperDump($data), $message); } private function getVarDumperDump($data) @@ -36,10 +36,9 @@ trait VarDumperTestTrait $dumper = new CliDumper($h); $dumper->setColors(false); $dumper->dump($cloner->cloneVar($data)->withRefHandles(false)); - fseek($h, 0); - $data = stream_get_contents($h); + $data = stream_get_contents($h, -1, 0); fclose($h); - return $data; + return rtrim($data); } } diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index 17448a9cc2..7351c04903 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -125,7 +125,6 @@ EOTXT current_line_number: 1 error_code: XML_ERROR_NONE } - EOTXT , $var @@ -239,7 +238,6 @@ array:3 [ ] 2 => &2 array:1 [&2] ] - EOTXT , $var