mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 15:22:17 +02:00
migration symfony 5 4 (#300)
* symfony 5.4 (diff dev) * symfony 5.4 (working) * symfony 5.4 (update autoload) * symfony 5.4 (remove swiftmailer mailer implementation) * symfony 5.4 (php doc and split Global accessor class) ### Impacted packages: composer require php:">=7.2.5 <8.0.0" symfony/console:5.4.* symfony/dotenv:5.4.* symfony/framework-bundle:5.4.* symfony/twig-bundle:5.4.* symfony/yaml:5.4.* --update-with-dependencies composer require symfony/stopwatch:5.4.* symfony/web-profiler-bundle:5.4.* --dev --update-with-dependencies
This commit is contained in:
@@ -29,15 +29,20 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
|
||||
'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'],
|
||||
|
||||
'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'],
|
||||
|
||||
'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'],
|
||||
'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'],
|
||||
'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'],
|
||||
'ReflectionAttribute' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castAttribute'],
|
||||
'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'],
|
||||
'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'],
|
||||
'ReflectionClassConstant' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClassConstant'],
|
||||
'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'],
|
||||
'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'],
|
||||
'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'],
|
||||
'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'],
|
||||
'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'],
|
||||
'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'],
|
||||
'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'],
|
||||
|
||||
@@ -70,18 +75,34 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'],
|
||||
'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'],
|
||||
|
||||
'XmlReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'],
|
||||
'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'],
|
||||
|
||||
'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'],
|
||||
'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'],
|
||||
'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'],
|
||||
'Symfony\Bridge\Monolog\Logger' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'Symfony\Component\HttpClient\AmpHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
|
||||
'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
|
||||
'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
|
||||
'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],
|
||||
'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],
|
||||
'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'],
|
||||
'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'],
|
||||
'Symfony\Component\Uid\Ulid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUlid'],
|
||||
'Symfony\Component\Uid\Uuid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUuid'],
|
||||
'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'],
|
||||
'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'],
|
||||
'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'],
|
||||
'Symfony\Component\Debug\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'],
|
||||
'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'],
|
||||
|
||||
'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'],
|
||||
|
||||
'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'],
|
||||
|
||||
'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'],
|
||||
'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
|
||||
@@ -106,23 +127,43 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'],
|
||||
'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
|
||||
'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'],
|
||||
|
||||
'MongoCursorInterface' => ['Symfony\Component\VarDumper\Caster\MongoCaster', 'castCursor'],
|
||||
'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'],
|
||||
|
||||
'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'],
|
||||
'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'],
|
||||
'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'],
|
||||
|
||||
'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'],
|
||||
'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'],
|
||||
'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'],
|
||||
'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'],
|
||||
|
||||
'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'],
|
||||
|
||||
'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'],
|
||||
'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'],
|
||||
'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'],
|
||||
'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'],
|
||||
'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'],
|
||||
|
||||
'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'],
|
||||
|
||||
'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'],
|
||||
'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'],
|
||||
'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'],
|
||||
'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'],
|
||||
|
||||
'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'],
|
||||
|
||||
'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'],
|
||||
':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'],
|
||||
|
||||
':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],
|
||||
':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'],
|
||||
|
||||
'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],
|
||||
':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'],
|
||||
|
||||
':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'],
|
||||
':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'],
|
||||
':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],
|
||||
@@ -130,18 +171,43 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'],
|
||||
':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'],
|
||||
':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],
|
||||
|
||||
'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],
|
||||
':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'],
|
||||
|
||||
':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'],
|
||||
':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'],
|
||||
|
||||
'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],
|
||||
':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'],
|
||||
|
||||
'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'],
|
||||
'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'],
|
||||
'RdKafka\KafkaConsumer' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castKafkaConsumer'],
|
||||
'RdKafka\Metadata\Broker' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castBrokerMetadata'],
|
||||
'RdKafka\Metadata\Collection' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castCollectionMetadata'],
|
||||
'RdKafka\Metadata\Partition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castPartitionMetadata'],
|
||||
'RdKafka\Metadata\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicMetadata'],
|
||||
'RdKafka\Message' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castMessage'],
|
||||
'RdKafka\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopic'],
|
||||
'RdKafka\TopicPartition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicPartition'],
|
||||
'RdKafka\TopicConf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicConf'],
|
||||
];
|
||||
|
||||
protected $maxItems = 2500;
|
||||
protected $maxString = -1;
|
||||
protected $minDepth = 1;
|
||||
protected $useExt;
|
||||
|
||||
/**
|
||||
* @var array<string, list<callable>>
|
||||
*/
|
||||
private $casters = [];
|
||||
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
private $prevErrorHandler;
|
||||
|
||||
private $classInfo = [];
|
||||
private $filter = 0;
|
||||
|
||||
@@ -156,7 +222,6 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
$casters = static::$defaultCasters;
|
||||
}
|
||||
$this->addCasters($casters);
|
||||
$this->useExt = \extension_loaded('symfony_debug');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,39 +237,33 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
public function addCasters(array $casters)
|
||||
{
|
||||
foreach ($casters as $type => $callback) {
|
||||
$this->casters[strtolower($type)][] = \is_string($callback) && false !== strpos($callback, '::') ? explode('::', $callback, 2) : $callback;
|
||||
$this->casters[$type][] = $callback;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of items to clone past the minimum depth in nested structures.
|
||||
*
|
||||
* @param int $maxItems
|
||||
*/
|
||||
public function setMaxItems($maxItems)
|
||||
public function setMaxItems(int $maxItems)
|
||||
{
|
||||
$this->maxItems = (int) $maxItems;
|
||||
$this->maxItems = $maxItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum cloned length for strings.
|
||||
*
|
||||
* @param int $maxString
|
||||
*/
|
||||
public function setMaxString($maxString)
|
||||
public function setMaxString(int $maxString)
|
||||
{
|
||||
$this->maxString = (int) $maxString;
|
||||
$this->maxString = $maxString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the minimum tree depth where we are guaranteed to clone all the items. After this
|
||||
* depth is reached, only setMaxItems items will be cloned.
|
||||
*
|
||||
* @param int $minDepth
|
||||
*/
|
||||
public function setMinDepth($minDepth)
|
||||
public function setMinDepth(int $minDepth)
|
||||
{
|
||||
$this->minDepth = (int) $minDepth;
|
||||
$this->minDepth = $minDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,9 +272,9 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
* @param mixed $var Any PHP variable
|
||||
* @param int $filter A bit field of Caster::EXCLUDE_* constants
|
||||
*
|
||||
* @return Data The cloned variable represented by a Data object
|
||||
* @return Data
|
||||
*/
|
||||
public function cloneVar($var, $filter = 0)
|
||||
public function cloneVar($var, int $filter = 0)
|
||||
{
|
||||
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) {
|
||||
if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) {
|
||||
@@ -224,7 +283,7 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
}
|
||||
|
||||
if ($this->prevErrorHandler) {
|
||||
return \call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context);
|
||||
return ($this->prevErrorHandler)($type, $msg, $file, $line, $context);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -250,46 +309,52 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
*
|
||||
* @param mixed $var Any PHP variable
|
||||
*
|
||||
* @return array The cloned variable represented in an array
|
||||
* @return array
|
||||
*/
|
||||
abstract protected function doClone($var);
|
||||
|
||||
/**
|
||||
* Casts an object to an array representation.
|
||||
*
|
||||
* @param Stub $stub The Stub for the casted object
|
||||
* @param bool $isNested True if the object is nested in the dumped structure
|
||||
*
|
||||
* @return array The object casted as array
|
||||
* @return array
|
||||
*/
|
||||
protected function castObject(Stub $stub, $isNested)
|
||||
protected function castObject(Stub $stub, bool $isNested)
|
||||
{
|
||||
$obj = $stub->value;
|
||||
$class = $stub->class;
|
||||
|
||||
if ((\PHP_VERSION_ID >= 80000 || (isset($class[15]) && "\0" === $class[15])) && false !== strpos($class, "@anonymous\0")) {
|
||||
$stub->class = \PHP_VERSION_ID < 80000 ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : get_debug_type($obj);
|
||||
if (\PHP_VERSION_ID < 80000 ? "\0" === ($class[15] ?? null) : str_contains($class, "@anonymous\0")) {
|
||||
$stub->class = get_debug_type($obj);
|
||||
}
|
||||
if (isset($this->classInfo[$class])) {
|
||||
list($i, $parents, $hasDebugInfo) = $this->classInfo[$class];
|
||||
[$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class];
|
||||
} else {
|
||||
$i = 2;
|
||||
$parents = [strtolower($class)];
|
||||
$parents = [$class];
|
||||
$hasDebugInfo = method_exists($class, '__debugInfo');
|
||||
|
||||
foreach (class_parents($class) as $p) {
|
||||
$parents[] = strtolower($p);
|
||||
$parents[] = $p;
|
||||
++$i;
|
||||
}
|
||||
foreach (class_implements($class) as $p) {
|
||||
$parents[] = strtolower($p);
|
||||
$parents[] = $p;
|
||||
++$i;
|
||||
}
|
||||
$parents[] = '*';
|
||||
|
||||
$this->classInfo[$class] = [$i, $parents, $hasDebugInfo];
|
||||
$r = new \ReflectionClass($class);
|
||||
$fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [
|
||||
'file' => $r->getFileName(),
|
||||
'line' => $r->getStartLine(),
|
||||
];
|
||||
|
||||
$this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo];
|
||||
}
|
||||
|
||||
$stub->attr += $fileInfo;
|
||||
$a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class);
|
||||
|
||||
try {
|
||||
@@ -310,12 +375,11 @@ abstract class AbstractCloner implements ClonerInterface
|
||||
/**
|
||||
* Casts a resource to an array representation.
|
||||
*
|
||||
* @param Stub $stub The Stub for the casted resource
|
||||
* @param bool $isNested True if the object is nested in the dumped structure
|
||||
*
|
||||
* @return array The resource casted as array
|
||||
* @return array
|
||||
*/
|
||||
protected function castResource(Stub $stub, $isNested)
|
||||
protected function castResource(Stub $stub, bool $isNested)
|
||||
{
|
||||
$a = [];
|
||||
$res = $stub->value;
|
||||
|
||||
@@ -21,7 +21,7 @@ interface ClonerInterface
|
||||
*
|
||||
* @param mixed $var Any PHP variable
|
||||
*
|
||||
* @return Data The cloned variable represented by a Data object
|
||||
* @return Data
|
||||
*/
|
||||
public function cloneVar($var);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ namespace Symfony\Component\VarDumper\Cloner;
|
||||
*/
|
||||
class Cursor
|
||||
{
|
||||
const HASH_INDEXED = Stub::ARRAY_INDEXED;
|
||||
const HASH_ASSOC = Stub::ARRAY_ASSOC;
|
||||
const HASH_OBJECT = Stub::TYPE_OBJECT;
|
||||
const HASH_RESOURCE = Stub::TYPE_RESOURCE;
|
||||
public const HASH_INDEXED = Stub::ARRAY_INDEXED;
|
||||
public const HASH_ASSOC = Stub::ARRAY_ASSOC;
|
||||
public const HASH_OBJECT = Stub::TYPE_OBJECT;
|
||||
public const HASH_RESOURCE = Stub::TYPE_RESOURCE;
|
||||
|
||||
public $depth = 0;
|
||||
public $refIndex = 0;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\VarDumper\Cloner;
|
||||
|
||||
use Symfony\Component\VarDumper\Caster\Caster;
|
||||
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
@@ -24,6 +25,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
private $maxDepth = 20;
|
||||
private $maxItemsPerDepth = -1;
|
||||
private $useRefHandles = -1;
|
||||
private $context = [];
|
||||
|
||||
/**
|
||||
* @param array $data An array as returned by ClonerInterface::cloneVar()
|
||||
@@ -34,7 +36,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null The type of the value
|
||||
* @return string|null
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
@@ -63,9 +65,11 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a native representation of the original value.
|
||||
*
|
||||
* @param array|bool $recursive Whether values should be resolved recursively or not
|
||||
*
|
||||
* @return string|int|float|bool|array|Data[]|null A native representation of the original value
|
||||
* @return string|int|float|bool|array|Data[]|null
|
||||
*/
|
||||
public function getValue($recursive = false)
|
||||
{
|
||||
@@ -106,23 +110,29 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
return $children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function count()
|
||||
{
|
||||
return \count($this->getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Traversable
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function getIterator()
|
||||
{
|
||||
if (!\is_array($value = $this->getValue())) {
|
||||
throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, \gettype($value)));
|
||||
throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value)));
|
||||
}
|
||||
|
||||
foreach ($value as $k => $v) {
|
||||
yield $k => $v;
|
||||
}
|
||||
yield from $value;
|
||||
}
|
||||
|
||||
public function __get($key)
|
||||
public function __get(string $key)
|
||||
{
|
||||
if (null !== $data = $this->seek($key)) {
|
||||
$item = $this->getStub($data->data[$data->position][$data->key]);
|
||||
@@ -133,31 +143,53 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
return null;
|
||||
}
|
||||
|
||||
public function __isset($key)
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset(string $key)
|
||||
{
|
||||
return null !== $this->seek($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetExists($key)
|
||||
{
|
||||
return $this->__isset($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetGet($key)
|
||||
{
|
||||
return $this->__get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetSet($key, $value)
|
||||
{
|
||||
throw new \BadMethodCallException(self::class.' objects are immutable.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function offsetUnset($key)
|
||||
{
|
||||
throw new \BadMethodCallException(self::class.' objects are immutable.');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$value = $this->getValue();
|
||||
@@ -169,29 +201,15 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
return sprintf('%s (count=%d)', $this->getType(), \count($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array The raw data structure
|
||||
*
|
||||
* @deprecated since version 3.3. Use array or object access instead.
|
||||
*/
|
||||
public function getRawData()
|
||||
{
|
||||
@trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the array or object access instead.', __METHOD__));
|
||||
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a depth limited clone of $this.
|
||||
*
|
||||
* @param int $maxDepth The max dumped depth level
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withMaxDepth($maxDepth)
|
||||
public function withMaxDepth(int $maxDepth)
|
||||
{
|
||||
$data = clone $this;
|
||||
$data->maxDepth = (int) $maxDepth;
|
||||
$data->maxDepth = $maxDepth;
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -199,14 +217,12 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
/**
|
||||
* Limits the number of elements per depth level.
|
||||
*
|
||||
* @param int $maxItemsPerDepth The max number of items dumped per depth level
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withMaxItemsPerDepth($maxItemsPerDepth)
|
||||
public function withMaxItemsPerDepth(int $maxItemsPerDepth)
|
||||
{
|
||||
$data = clone $this;
|
||||
$data->maxItemsPerDepth = (int) $maxItemsPerDepth;
|
||||
$data->maxItemsPerDepth = $maxItemsPerDepth;
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -218,7 +234,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withRefHandles($useRefHandles)
|
||||
public function withRefHandles(bool $useRefHandles)
|
||||
{
|
||||
$data = clone $this;
|
||||
$data->useRefHandles = $useRefHandles ? -1 : 0;
|
||||
@@ -226,12 +242,23 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return static
|
||||
*/
|
||||
public function withContext(array $context)
|
||||
{
|
||||
$data = clone $this;
|
||||
$data->context = $context;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seeks to a specific key in nested data structures.
|
||||
*
|
||||
* @param string|int $key The key to seek to
|
||||
*
|
||||
* @return static|null Null if the key is not set
|
||||
* @return static|null
|
||||
*/
|
||||
public function seek($key)
|
||||
{
|
||||
@@ -280,18 +307,26 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
public function dump(DumperInterface $dumper)
|
||||
{
|
||||
$refs = [0];
|
||||
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
|
||||
$cursor = new Cursor();
|
||||
|
||||
if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) {
|
||||
$cursor->attr['if_links'] = true;
|
||||
$cursor->hashType = -1;
|
||||
$dumper->dumpScalar($cursor, 'default', '^');
|
||||
$cursor->attr = ['if_links' => true];
|
||||
$dumper->dumpScalar($cursor, 'default', ' ');
|
||||
$cursor->hashType = 0;
|
||||
}
|
||||
|
||||
$this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Depth-first dumping of items.
|
||||
*
|
||||
* @param DumperInterface $dumper The dumper being used for dumping
|
||||
* @param Cursor $cursor A cursor used for tracking dumper state position
|
||||
* @param array &$refs A map of all references discovered while dumping
|
||||
* @param mixed $item A Stub object or the original value being dumped
|
||||
* @param mixed $item A Stub object or the original value being dumped
|
||||
*/
|
||||
private function dumpItem($dumper, $cursor, &$refs, $item)
|
||||
private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item)
|
||||
{
|
||||
$cursor->refIndex = 0;
|
||||
$cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
|
||||
@@ -313,7 +348,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
}
|
||||
$cursor->hardRefTo = $refs[$r];
|
||||
$cursor->hardRefHandle = $this->useRefHandles & $item->handle;
|
||||
$cursor->hardRefCount = $item->refCount;
|
||||
$cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0;
|
||||
}
|
||||
$cursor->attr = $item->attr;
|
||||
$type = $item->class ?: \gettype($item->value);
|
||||
@@ -389,17 +424,9 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
|
||||
/**
|
||||
* Dumps children of hash structures.
|
||||
*
|
||||
* @param DumperInterface $dumper
|
||||
* @param Cursor $parentCursor The cursor of the parent hash
|
||||
* @param array &$refs A map of all references discovered while dumping
|
||||
* @param array $children The children to dump
|
||||
* @param int $hashCut The number of items removed from the original hash
|
||||
* @param string $hashType A Cursor::HASH_* const
|
||||
* @param bool $dumpKeys Whether keys should be dumped or not
|
||||
*
|
||||
* @return int The final number of removed items
|
||||
*/
|
||||
private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType, $dumpKeys)
|
||||
private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int
|
||||
{
|
||||
$cursor = clone $parentCursor;
|
||||
++$cursor->depth;
|
||||
|
||||
@@ -21,40 +21,36 @@ interface DumperInterface
|
||||
/**
|
||||
* Dumps a scalar value.
|
||||
*
|
||||
* @param Cursor $cursor The Cursor position in the dump
|
||||
* @param string $type The PHP type of the value being dumped
|
||||
* @param string|int|float|bool $value The scalar value being dumped
|
||||
* @param string $type The PHP type of the value being dumped
|
||||
* @param string|int|float|bool $value The scalar value being dumped
|
||||
*/
|
||||
public function dumpScalar(Cursor $cursor, $type, $value);
|
||||
public function dumpScalar(Cursor $cursor, string $type, $value);
|
||||
|
||||
/**
|
||||
* Dumps a string.
|
||||
*
|
||||
* @param Cursor $cursor The Cursor position in the dump
|
||||
* @param string $str The string being dumped
|
||||
* @param bool $bin Whether $str is UTF-8 or binary encoded
|
||||
* @param int $cut The number of characters $str has been cut by
|
||||
* @param string $str The string being dumped
|
||||
* @param bool $bin Whether $str is UTF-8 or binary encoded
|
||||
* @param int $cut The number of characters $str has been cut by
|
||||
*/
|
||||
public function dumpString(Cursor $cursor, $str, $bin, $cut);
|
||||
public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut);
|
||||
|
||||
/**
|
||||
* Dumps while entering an hash.
|
||||
*
|
||||
* @param Cursor $cursor The Cursor position in the dump
|
||||
* @param int $type A Cursor::HASH_* const for the type of hash
|
||||
* @param string|int $class The object class, resource type or array count
|
||||
* @param bool $hasChild When the dump of the hash has child item
|
||||
*/
|
||||
public function enterHash(Cursor $cursor, $type, $class, $hasChild);
|
||||
public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild);
|
||||
|
||||
/**
|
||||
* Dumps while leaving an hash.
|
||||
*
|
||||
* @param Cursor $cursor The Cursor position in the dump
|
||||
* @param int $type A Cursor::HASH_* const for the type of hash
|
||||
* @param string|int $class The object class, resource type or array count
|
||||
* @param bool $hasChild When the dump of the hash has child item
|
||||
* @param int $cut The number of items the hash has been cut by
|
||||
*/
|
||||
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
|
||||
public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut);
|
||||
}
|
||||
|
||||
@@ -18,17 +18,17 @@ namespace Symfony\Component\VarDumper\Cloner;
|
||||
*/
|
||||
class Stub
|
||||
{
|
||||
const TYPE_REF = 1;
|
||||
const TYPE_STRING = 2;
|
||||
const TYPE_ARRAY = 3;
|
||||
const TYPE_OBJECT = 4;
|
||||
const TYPE_RESOURCE = 5;
|
||||
public const TYPE_REF = 1;
|
||||
public const TYPE_STRING = 2;
|
||||
public const TYPE_ARRAY = 3;
|
||||
public const TYPE_OBJECT = 4;
|
||||
public const TYPE_RESOURCE = 5;
|
||||
|
||||
const STRING_BINARY = 1;
|
||||
const STRING_UTF8 = 2;
|
||||
public const STRING_BINARY = 1;
|
||||
public const STRING_UTF8 = 2;
|
||||
|
||||
const ARRAY_ASSOC = 1;
|
||||
const ARRAY_INDEXED = 2;
|
||||
public const ARRAY_ASSOC = 1;
|
||||
public const ARRAY_INDEXED = 2;
|
||||
|
||||
public $type = self::TYPE_REF;
|
||||
public $class = '';
|
||||
@@ -44,7 +44,7 @@ class Stub
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function __sleep()
|
||||
public function __sleep(): array
|
||||
{
|
||||
$properties = [];
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ namespace Symfony\Component\VarDumper\Cloner;
|
||||
class VarCloner extends AbstractCloner
|
||||
{
|
||||
private static $gid;
|
||||
private static $hashMask = 0;
|
||||
private static $hashOffset = 0;
|
||||
private static $arrayCache = [];
|
||||
|
||||
/**
|
||||
@@ -29,13 +27,12 @@ class VarCloner extends AbstractCloner
|
||||
$len = 1; // Length of $queue
|
||||
$pos = 0; // Number of cloned items past the minimum depth
|
||||
$refsCounter = 0; // Hard references counter
|
||||
$queue = [[$var]]; // This breadth-first queue is the return value
|
||||
$indexedArrays = []; // Map of queue indexes that hold numerically indexed arrays
|
||||
$hardRefs = []; // Map of original zval hashes to stub objects
|
||||
$objRefs = []; // Map of original object handles to their stub object counterpart
|
||||
$objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning
|
||||
$resRefs = []; // Map of original resource handles to their stub object counterpart
|
||||
$values = []; // Map of stub objects' hashes to original values
|
||||
$queue = [[$var]]; // This breadth-first queue is the return value
|
||||
$hardRefs = []; // Map of original zval ids to stub objects
|
||||
$objRefs = []; // Map of original object handles to their stub object counterpart
|
||||
$objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning
|
||||
$resRefs = []; // Map of original resource handles to their stub object counterpart
|
||||
$values = []; // Map of stub objects' ids to original values
|
||||
$maxItems = $this->maxItems;
|
||||
$maxString = $this->maxString;
|
||||
$minDepth = $this->minDepth;
|
||||
@@ -47,13 +44,9 @@ class VarCloner extends AbstractCloner
|
||||
$stub = null; // Stub capturing the main properties of an original item value
|
||||
// or null if the original value is used directly
|
||||
|
||||
if (!self::$hashMask) {
|
||||
self::initHashMask();
|
||||
self::$gid = md5(dechex(self::$hashMask)); // Unique string used to detect the special $GLOBALS variable
|
||||
if (!$gid = self::$gid) {
|
||||
$gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable
|
||||
}
|
||||
$gid = self::$gid;
|
||||
$hashMask = self::$hashMask;
|
||||
$hashOffset = self::$hashOffset;
|
||||
$arrayStub = new Stub();
|
||||
$arrayStub->type = Stub::TYPE_ARRAY;
|
||||
$fromObjCast = false;
|
||||
@@ -69,50 +62,45 @@ class VarCloner extends AbstractCloner
|
||||
}
|
||||
|
||||
$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 ([$k => true] as $gk => $gv) {
|
||||
}
|
||||
if ($gk !== $k) {
|
||||
$fromObjCast = true;
|
||||
$refs = $vals = array_values($queue[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($vals as $k => $v) {
|
||||
// $v is the original value or a stub object in case of hard references
|
||||
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$zvalIsRef = null !== \ReflectionReference::fromArrayElement($vals, $k);
|
||||
$zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null;
|
||||
} else {
|
||||
$refs[$k] = $cookie;
|
||||
$zvalIsRef = $vals[$k] === $cookie;
|
||||
$zvalRef = $vals[$k] === $cookie;
|
||||
}
|
||||
|
||||
if ($zvalIsRef) {
|
||||
if ($zvalRef) {
|
||||
$vals[$k] = &$stub; // Break hard references to make $queue completely
|
||||
unset($stub); // independent from the original structure
|
||||
if ($v instanceof Stub && isset($hardRefs[spl_object_hash($v)])) {
|
||||
$vals[$k] = $refs[$k] = $v;
|
||||
if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) {
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$v = $vals[$k];
|
||||
} else {
|
||||
$refs[$k] = $vals[$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] = new Stub();
|
||||
$vals[$k]->value = $v;
|
||||
$vals[$k]->handle = ++$refsCounter;
|
||||
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$hardRefs[$zvalRef] = $vals[$k];
|
||||
} else {
|
||||
$refs[$k] = $vals[$k];
|
||||
$h = spl_object_id($refs[$k]);
|
||||
$hardRefs[$h] = &$refs[$k];
|
||||
$values[$h] = $v;
|
||||
}
|
||||
}
|
||||
// Create $stub when the original value $v can not be used directly
|
||||
// Create $stub when the original value $v cannot be used directly
|
||||
// If $v is a nested structure, put that structure in array $a
|
||||
switch (true) {
|
||||
case null === $v:
|
||||
@@ -151,41 +139,55 @@ class VarCloner extends AbstractCloner
|
||||
continue 2;
|
||||
}
|
||||
$stub = $arrayStub;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80100) {
|
||||
$stub->class = array_is_list($v) ? Stub::ARRAY_INDEXED : Stub::ARRAY_ASSOC;
|
||||
$a = $v;
|
||||
break;
|
||||
}
|
||||
|
||||
$stub->class = Stub::ARRAY_INDEXED;
|
||||
|
||||
$j = -1;
|
||||
foreach ($v as $gk => $gv) {
|
||||
if ($gk !== ++$j) {
|
||||
$stub->class = Stub::ARRAY_ASSOC;
|
||||
$a = $v;
|
||||
$a[$gid] = true;
|
||||
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[$gid] = true;
|
||||
|
||||
// Happens with copies of $GLOBALS
|
||||
if (isset($v[$gid])) {
|
||||
unset($v[$gid]);
|
||||
$a = [];
|
||||
foreach ($v as $gk => &$gv) {
|
||||
$a[$gk] = &$gv;
|
||||
// Copies of $GLOBALS have very strange behavior,
|
||||
// let's detect them with some black magic
|
||||
if (isset($v[$gid])) {
|
||||
unset($v[$gid]);
|
||||
$a = [];
|
||||
foreach ($v as $gk => &$gv) {
|
||||
if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) {
|
||||
unset($v);
|
||||
$v = new Stub();
|
||||
$v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0];
|
||||
$v->handle = -1;
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
$gv = &$a[$gk];
|
||||
$hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv;
|
||||
} else {
|
||||
$gv = &$hardRefs[spl_object_id($v)];
|
||||
}
|
||||
$gv = $v;
|
||||
}
|
||||
unset($gv);
|
||||
} else {
|
||||
$a = $v;
|
||||
|
||||
$a[$gk] = &$gv;
|
||||
}
|
||||
} elseif (\PHP_VERSION_ID < 70200) {
|
||||
$indexedArrays[$len] = true;
|
||||
unset($gv);
|
||||
} else {
|
||||
$a = $v;
|
||||
}
|
||||
break;
|
||||
|
||||
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))])) {
|
||||
if (empty($objRefs[$h = spl_object_id($v)])) {
|
||||
$stub = new Stub();
|
||||
$stub->type = Stub::TYPE_OBJECT;
|
||||
$stub->class = \get_class($v);
|
||||
@@ -196,8 +198,7 @@ class VarCloner extends AbstractCloner
|
||||
if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
|
||||
break;
|
||||
}
|
||||
$h = $hashMask ^ hexdec(substr(spl_object_hash($stub->value), $hashOffset, \PHP_INT_SIZE));
|
||||
$stub->handle = $h;
|
||||
$stub->handle = $h = spl_object_id($stub->value);
|
||||
}
|
||||
$stub->value = null;
|
||||
if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
|
||||
@@ -271,10 +272,12 @@ class VarCloner extends AbstractCloner
|
||||
}
|
||||
}
|
||||
|
||||
if ($zvalIsRef) {
|
||||
$refs[$k]->value = $stub;
|
||||
} else {
|
||||
if (!$zvalRef) {
|
||||
$vals[$k] = $stub;
|
||||
} elseif (\PHP_VERSION_ID >= 70400) {
|
||||
$hardRefs[$zvalRef]->value = $stub;
|
||||
} else {
|
||||
$refs[$k]->value = $stub;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,31 +308,4 @@ class VarCloner extends AbstractCloner
|
||||
|
||||
return $queue;
|
||||
}
|
||||
|
||||
private static function initHashMask()
|
||||
{
|
||||
$obj = (object) [];
|
||||
self::$hashOffset = 16 - \PHP_INT_SIZE;
|
||||
self::$hashMask = -1;
|
||||
|
||||
if (\defined('HHVM_VERSION')) {
|
||||
self::$hashOffset += 16;
|
||||
} else {
|
||||
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
|
||||
$obFuncs = ['ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush'];
|
||||
foreach (debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
|
||||
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && \in_array($frame['function'], $obFuncs)) {
|
||||
$frame['line'] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!empty($frame['line'])) {
|
||||
ob_start();
|
||||
debug_zval_dump($obj);
|
||||
self::$hashMask = (int) substr(ob_get_clean(), 17);
|
||||
}
|
||||
}
|
||||
|
||||
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), self::$hashOffset, \PHP_INT_SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user