diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 45e0b6ad771b1..8fd192d0e402c 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -213,7 +213,7 @@ public function cloneVar($var, $filter = 0) gc_disable(); } try { - $data = $this->doClone($var); + return new Data($this->doClone($var)); } finally { if ($gc) { gc_enable(); @@ -221,8 +221,6 @@ public function cloneVar($var, $filter = 0) restore_error_handler(); $this->prevErrorHandler = null; } - - return new Data($data); } /** diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 655fae0ca6fe5..b3d0cfab495ac 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -16,7 +16,7 @@ /** * @author Nicolas Grekas */ -class Data implements \ArrayAccess, \Countable, \IteratorAggregate, \Serializable +class Data implements \ArrayAccess, \Countable, \IteratorAggregate { private $data; private $position = 0; @@ -72,7 +72,7 @@ public function getValue($recursive = false) if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { $item = $item->value; } - if (!$item instanceof Stub) { + if (!($item = $this->getStub($item)) instanceof Stub) { return $item; } if (Stub::TYPE_STRING === $item->type) { @@ -82,7 +82,7 @@ public function getValue($recursive = false) $children = $item->position ? $this->data[$item->position] : array(); foreach ($children as $k => $v) { - if ($recursive && !$v instanceof Stub) { + if ($recursive && !($v = $this->getStub($v)) instanceof Stub) { continue; } $children[$k] = clone $this; @@ -90,12 +90,12 @@ public function getValue($recursive = false) $children[$k]->position = $item->position; if ($recursive) { - if ($v instanceof Stub && Stub::TYPE_REF === $v->type && $v->value instanceof Stub) { + if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) { $recursive = (array) $recursive; - if (isset($recursive[$v->value->position])) { + if (isset($recursive[$v->position])) { continue; } - $recursive[$v->value->position] = true; + $recursive[$v->position] = true; } $children[$k] = $children[$k]->getValue($recursive); } @@ -123,7 +123,7 @@ public function getIterator() public function __get($key) { if (null !== $data = $this->seek($key)) { - $item = $data->data[$data->position][$data->key]; + $item = $this->getStub($data->data[$data->position][$data->key]); return $item instanceof Stub || array() === $item ? $data : $item; } @@ -236,7 +236,7 @@ public function seek($key) if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { $item = $item->value; } - if (!$item instanceof Stub || !$item->position) { + if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) { return; } $keys = array($key); @@ -278,57 +278,6 @@ public function dump(DumperInterface $dumper) $this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]); } - /** - * @internal - */ - public function serialize() - { - $data = $this->data; - - foreach ($data as $i => $values) { - foreach ($values as $k => $v) { - if ($v instanceof Stub) { - if (Stub::TYPE_ARRAY === $v->type) { - $v = self::mapStubConsts($v, false); - $data[$i][$k] = array($v->class, $v->position, $v->cut); - } else { - $v = self::mapStubConsts($v, false); - $data[$i][$k] = array($v->class, $v->position, $v->cut, $v->type, $v->value, $v->handle, $v->refCount, $v->attr); - } - } - } - } - - return serialize(array($data, $this->position, $this->key, $this->maxDepth, $this->maxItemsPerDepth, $this->useRefHandles)); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($data, $this->position, $this->key, $this->maxDepth, $this->maxItemsPerDepth, $this->useRefHandles) = unserialize($serialized); - - foreach ($data as $i => $values) { - foreach ($values as $k => $v) { - if ($v && is_array($v)) { - $s = new Stub(); - if (3 === count($v)) { - $s->type = Stub::TYPE_ARRAY; - $s = self::mapStubConsts($s, false); - list($s->class, $s->position, $s->cut) = $v; - $s->value = $s->cut + count($data[$s->position]); - } else { - list($s->class, $s->position, $s->cut, $s->type, $s->value, $s->handle, $s->refCount, $s->attr) = $v; - } - $data[$i][$k] = self::mapStubConsts($s, true); - } - } - } - - $this->data = $data; - } - /** * Depth-first dumping of items. * @@ -346,7 +295,10 @@ private function dumpItem($dumper, $cursor, &$refs, $item) if (!$item instanceof Stub) { $cursor->attr = array(); - $type = gettype($item); + $type = \gettype($item); + if ($item && 'array' === $type) { + $item = $this->getStub($item); + } } elseif (Stub::TYPE_REF === $item->type) { if ($item->handle) { if (!isset($refs[$r = $item->handle - (PHP_INT_MAX >> 1)])) { @@ -360,7 +312,7 @@ private function dumpItem($dumper, $cursor, &$refs, $item) } $cursor->attr = $item->attr; $type = $item->class ?: gettype($item->value); - $item = $item->value; + $item = $this->getStub($item->value); } if ($item instanceof Stub) { if ($item->refCount) { @@ -458,21 +410,20 @@ private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCu return $hashCut; } - private static function mapStubConsts(Stub $stub, $resolve) + private function getStub($item) { - static $stubConstIndexes, $stubConstValues; - - if (null === $stubConstIndexes) { - $r = new \ReflectionClass(Stub::class); - $stubConstIndexes = array_flip(array_values($r->getConstants())); - $stubConstValues = array_flip($stubConstIndexes); + if (!$item || !\is_array($item)) { + return $item; } - $map = $resolve ? $stubConstValues : $stubConstIndexes; - - $stub = clone $stub; - $stub->type = $map[$stub->type]; - $stub->class = isset($map[$stub->class]) ? $map[$stub->class] : $stub->class; + $stub = new Stub(); + $stub->type = Stub::TYPE_ARRAY; + foreach ($item as $stub->class => $stub->position) { + } + if (isset($item[0])) { + $stub->cut = $item[0]; + } + $stub->value = $stub->cut + \count($this->data[$stub->position]); return $stub; } diff --git a/src/Symfony/Component/VarDumper/Cloner/Stub.php b/src/Symfony/Component/VarDumper/Cloner/Stub.php index 313c591fc835a..3b8e60d90ee6e 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Stub.php +++ b/src/Symfony/Component/VarDumper/Cloner/Stub.php @@ -16,19 +16,19 @@ * * @author Nicolas Grekas */ -class Stub +class Stub implements \Serializable { - const TYPE_REF = 'ref'; - const TYPE_STRING = 'string'; - const TYPE_ARRAY = 'array'; - const TYPE_OBJECT = 'object'; - const TYPE_RESOURCE = 'resource'; + const TYPE_REF = 1; + const TYPE_STRING = 2; + const TYPE_ARRAY = 3; + const TYPE_OBJECT = 4; + const TYPE_RESOURCE = 5; - const STRING_BINARY = 'bin'; - const STRING_UTF8 = 'utf8'; + const STRING_BINARY = 1; + const STRING_UTF8 = 2; - const ARRAY_ASSOC = 'assoc'; - const ARRAY_INDEXED = 'indexed'; + const ARRAY_ASSOC = 1; + const ARRAY_INDEXED = 2; public $type = self::TYPE_REF; public $class = ''; @@ -38,4 +38,20 @@ class Stub public $refCount = 0; public $position = 0; public $attr = array(); + + /** + * @internal + */ + public function serialize() + { + return \serialize(array($this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr)); + } + + /** + * @internal + */ + public function unserialize($serialized) + { + list($this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr) = \unserialize($serialized); + } } diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index 6a3b451bda7f7..108ab01e17652 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -24,12 +24,11 @@ class VarCloner extends AbstractCloner */ protected function doClone($var) { - $useExt = $this->useExt; $len = 1; // Length of $queue $pos = 0; // Number of cloned items past the first level $refsCounter = 0; // Hard references counter $queue = array(array($var)); // This breadth-first queue is the return value - $arrayRefs = array(); // Map of queue indexes to stub array objects + $indexedArrays = array(); // Map of queue indexes that hold numerically indexed arrays $hardRefs = array(); // Map of original zval hashes to stub objects $objRefs = array(); // Map of original object handles to their stub object couterpart $resRefs = array(); // Map of original resource handles to their stub object couterpart @@ -41,92 +40,99 @@ protected function doClone($var) $a = null; // Array cast for nested structures $stub = null; // Stub capturing the main properties of an original item value // or null if the original value is used directly - $zval = array( // Main properties of the current value - 'type' => null, - 'zval_isref' => null, - 'zval_hash' => null, - 'array_count' => null, - 'object_class' => null, - 'object_handle' => null, - 'resource_type' => null, - ); + if (!self::$hashMask) { self::initHashMask(); } $hashMask = self::$hashMask; $hashOffset = self::$hashOffset; + $arrayStub = new Stub(); + $arrayStub->type = Stub::TYPE_ARRAY; + $fromObjCast = false; for ($i = 0; $i < $len; ++$i) { - $indexed = true; // Whether the currently iterated array is numerically indexed or not - $j = -1; // Position in the currently iterated array - $fromObjCast = array_keys($queue[$i]); - $fromObjCast = array_keys(array_flip($fromObjCast)) !== $fromObjCast; - $refs = $vals = $fromObjCast ? array_values($queue[$i]) : $queue[$i]; - foreach ($queue[$i] as $k => $v) { - // $k is the original key - // $v is the original value or a stub object in case of hard references - if ($k !== ++$j) { - $indexed = false; - } - if ($fromObjCast) { - $k = $j; - } - if ($useExt) { - $zval = symfony_zval_info($k, $refs); - } else { - $refs[$k] = $cookie; - if ($zval['zval_isref'] = $vals[$k] === $cookie) { - $zval['zval_hash'] = $v instanceof Stub ? spl_object_hash($v) : null; + $refs = $vals = $queue[$i]; + if (\PHP_VERSION_ID < 70200 && empty($indexedArrays[$i])) { + // see https://wiki.php.net/rfc/convert_numeric_keys_in_object_array_casts + foreach ($vals as $k => $v) { + if (\is_int($k)) { + continue; + } + foreach (array($k => true) as $j => $v) { + } + if ($k !== $j) { + $fromObjCast = true; + $refs = $vals = \array_values($queue[$i]); + break; } - $zval['type'] = gettype($v); } - if ($zval['zval_isref']) { + } + foreach ($vals as $k => $v) { + // $v is the original value or a stub object in case of hard references + $refs[$k] = $cookie; + if ($zvalIsRef = $vals[$k] === $cookie) { $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure - if (isset($hardRefs[$zval['zval_hash']])) { - $vals[$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($refs[$k] = $v); + if ($v instanceof Stub && isset($hardRefs[\spl_object_hash($v)])) { + $vals[$k] = $refs[$k] = $v; if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } ++$v->refCount; continue; } + $refs[$k] = $vals[$k] = new Stub(); + $refs[$k]->value = $v; + $h = \spl_object_hash($refs[$k]); + $hardRefs[$h] = &$refs[$k]; + $values[$h] = $v; + $vals[$k]->handle = ++$refsCounter; } // Create $stub when the original value $v can not be used directly // If $v is a nested structure, put that structure in array $a - switch ($zval['type']) { - case 'string': - if (isset($v[0]) && !preg_match('//u', $v)) { + switch (true) { + case empty($v): + case true === $v: + case \is_int($v): + case \is_float($v): + break; + + case \is_string($v): + if (!\preg_match('//u', $v)) { $stub = new Stub(); $stub->type = Stub::TYPE_STRING; $stub->class = Stub::STRING_BINARY; - if (0 <= $maxString && 0 < $cut = strlen($v) - $maxString) { + if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) { $stub->cut = $cut; - $stub->value = substr($v, 0, -$cut); + $stub->value = \substr($v, 0, -$cut); } else { $stub->value = $v; } - } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) { + } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = \mb_strlen($v, 'UTF-8') - $maxString) { $stub = new Stub(); $stub->type = Stub::TYPE_STRING; $stub->class = Stub::STRING_UTF8; $stub->cut = $cut; - $stub->value = mb_substr($v, 0, $maxString, 'UTF-8'); + $stub->value = \mb_substr($v, 0, $maxString, 'UTF-8'); } break; - case 'integer': - break; + case \is_array($v): + $stub = $arrayStub; + $stub->class = Stub::ARRAY_INDEXED; - case 'array': - if ($v) { - $stub = $arrayRefs[$len] = new Stub(); - $stub->type = Stub::TYPE_ARRAY; - $stub->class = Stub::ARRAY_ASSOC; + $j = -1; + foreach ($v as $gk => $gv) { + if ($gk !== ++$j) { + $stub->class = Stub::ARRAY_ASSOC; + break; + } + } + $a = $v; + if (Stub::ARRAY_ASSOC === $stub->class) { // Copies of $GLOBALS have very strange behavior, // let's detect them with some black magic - $a = $v; $a[$gid] = true; // Happens with copies of $GLOBALS @@ -136,19 +142,23 @@ protected function doClone($var) foreach ($v as $gk => &$gv) { $a[$gk] = &$gv; } + unset($gv); } else { $a = $v; } - - $stub->value = $zval['array_count'] ?: count($a); + } else { + $indexedArrays[$len] = true; } + + $stub->value = \count($a); break; - case 'object': - if (empty($objRefs[$h = $zval['object_handle'] ?: ($hashMask ^ hexdec(substr(spl_object_hash($v), $hashOffset, PHP_INT_SIZE)))])) { + case \is_object($v): + case $v instanceof \__PHP_Incomplete_Class: + if (empty($objRefs[$h = $hashMask ^ \hexdec(\substr(\spl_object_hash($v), $hashOffset, \PHP_INT_SIZE))])) { $stub = new Stub(); $stub->type = Stub::TYPE_OBJECT; - $stub->class = $zval['object_class'] ?: get_class($v); + $stub->class = \get_class($v); $stub->value = $v; $stub->handle = $h; $a = $this->castObject($stub, 0 < $i); @@ -156,18 +166,12 @@ protected function doClone($var) if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) { break; } - if ($useExt) { - $zval['type'] = $stub->value; - $zval = symfony_zval_info('type', $zval); - $h = $zval['object_handle']; - } else { - $h = $hashMask ^ hexdec(substr(spl_object_hash($stub->value), $hashOffset, PHP_INT_SIZE)); - } + $h = $hashMask ^ \hexdec(\substr(\spl_object_hash($stub->value), $hashOffset, \PHP_INT_SIZE)); $stub->handle = $h; } $stub->value = null; if (0 <= $maxItems && $maxItems <= $pos) { - $stub->cut = count($a); + $stub->cut = \count($a); $a = null; } } @@ -180,13 +184,11 @@ protected function doClone($var) } break; - case 'resource': - case 'unknown type': - case 'resource (closed)': + default: // resource if (empty($resRefs[$h = (int) $v])) { $stub = new Stub(); $stub->type = Stub::TYPE_RESOURCE; - if ('Unknown' === $stub->class = $zval['resource_type'] ?: @get_resource_type($v)) { + if ('Unknown' === $stub->class = @\get_resource_type($v)) { $stub->class = 'Closed'; } $stub->value = $v; @@ -194,7 +196,7 @@ protected function doClone($var) $a = $this->castResource($stub, 0 < $i); $stub->value = null; if (0 <= $maxItems && $maxItems <= $pos) { - $stub->cut = count($a); + $stub->cut = \count($a); $a = null; } } @@ -209,66 +211,51 @@ protected function doClone($var) } if (isset($stub)) { - if ($zval['zval_isref']) { - if ($useExt) { - $vals[$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub(); - $v->value = $stub; - } else { - $refs[$k] = new Stub(); - $refs[$k]->value = $stub; - $h = spl_object_hash($refs[$k]); - $vals[$k] = $hardRefs[$h] = &$refs[$k]; - $values[$h] = $v; - } - $vals[$k]->handle = ++$refsCounter; - } else { - $vals[$k] = $stub; - } - if ($a) { - if ($i && 0 <= $maxItems) { - $k = count($a); - if ($pos < $maxItems) { - if ($maxItems < $pos += $k) { - $a = array_slice($a, 0, $maxItems - $pos); - if ($stub->cut >= 0) { - $stub->cut += $pos - $maxItems; - } - } - } else { + if (!$i || 0 > $maxItems) { + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($pos < $maxItems) { + if ($maxItems < $pos += \count($a)) { + $a = \array_slice($a, 0, $maxItems - $pos); if ($stub->cut >= 0) { - $stub->cut += $k; + $stub->cut += $pos - $maxItems; } - $stub = $a = null; - unset($arrayRefs[$len]); - continue; } + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($stub->cut >= 0) { + $stub->cut += \count($a); + $stub->position = 0; } - $queue[$len] = $a; - $stub->position = $len++; } - $stub = $a = null; - } elseif ($zval['zval_isref']) { - if ($useExt) { - $vals[$k] = $hardRefs[$zval['zval_hash']] = new Stub(); - $vals[$k]->value = $v; + + if ($arrayStub === $stub) { + if ($arrayStub->cut) { + $stub = array($arrayStub->cut, $arrayStub->class => $arrayStub->position); + $arrayStub->cut = 0; + } else { + $stub = array($arrayStub->class => $arrayStub->position); + } + } + + if ($zvalIsRef) { + $refs[$k]->value = $stub; } else { - $refs[$k] = $vals[$k] = new Stub(); - $refs[$k]->value = $v; - $h = spl_object_hash($refs[$k]); - $hardRefs[$h] = &$refs[$k]; - $values[$h] = $v; + $vals[$k] = $stub; } - $vals[$k]->handle = ++$refsCounter; + + $stub = $a = null; } } if ($fromObjCast) { + $fromObjCast = false; $refs = $vals; $vals = array(); $j = -1; foreach ($queue[$i] as $k => $v) { - foreach (array($k => $v) as $a => $v) { + foreach (array($k => true) as $a => $v) { } if ($a !== $k) { $vals = (object) $vals; @@ -281,13 +268,7 @@ protected function doClone($var) } $queue[$i] = $vals; - - if (isset($arrayRefs[$i])) { - if ($indexed) { - $arrayRefs[$i]->class = Stub::ARRAY_INDEXED; - } - unset($arrayRefs[$i]); - } + unset($indexedArrays[$i]); } foreach ($values as $h => $v) { diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index 75774170f32ee..8509afaaccb24 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -33,19 +33,9 @@ public function testMaxIntBoundary() ( [0] => Array ( - [0] => Symfony\Component\VarDumper\Cloner\Stub Object + [0] => Array ( - [type] => array - [class] => assoc - [value] => 1 - [cut] => 0 - [handle] => 0 - [refCount] => 0 - [position] => 1 - [attr] => Array - ( - ) - + [1] => 1 ) ) @@ -84,7 +74,7 @@ public function testClone() ( [0] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => object + [type] => 4 [class] => stdClass [value] => [cut] => 0 @@ -103,7 +93,7 @@ public function testClone() ( [\000+\0001] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => object + [type] => 4 [class] => stdClass [value] => [cut] => 0 @@ -118,7 +108,7 @@ public function testClone() [\000+\0002] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => object + [type] => 4 [class] => stdClass [value] => [cut] => 0 @@ -174,24 +164,9 @@ public function testJsonCast() [0]=> array(1) { [0]=> - object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) { - ["type"]=> - string(5) "array" - ["class"]=> - string(5) "assoc" - ["value"]=> + array(1) { + [1]=> int(1) - ["cut"]=> - int(0) - ["handle"]=> - int(0) - ["refCount"]=> - int(0) - ["position"]=> - int(1) - ["attr"]=> - array(0) { - } } } [1]=> @@ -199,7 +174,7 @@ public function testJsonCast() ["1"]=> object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) { ["type"]=> - string(6) "object" + int(4) ["class"]=> string(8) "stdClass" ["value"]=> @@ -259,7 +234,7 @@ public function testCaster() ( [0] => Symfony\Component\VarDumper\Cloner\Stub Object ( - [type] => object + [type] => 4 [class] => %s [value] => [cut] => 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