updated-packages

This commit is contained in:
RafficMohammed
2023-01-08 00:13:22 +05:30
parent 3ff7df7487
commit da241bacb6
12659 changed files with 563377 additions and 510538 deletions

View File

@@ -1,3 +0,0 @@
composer.lock
phpunit.xml
vendor/

View File

@@ -1,6 +1,22 @@
CHANGELOG
=========
4.4.0
-----
* added `VarDumperTestTrait::setUpVarDumper()` and `VarDumperTestTrait::tearDownVarDumper()`
to configure casters & flags to use in tests
* added `ImagineCaster` and infrastructure to dump images
* added the stamps of a message after it is dispatched in `TraceableMessageBus` and `MessengerDataCollector` collected data
* added `UuidCaster`
* made all casters final
* added support for the `NO_COLOR` env var (https://no-color.org/)
4.3.0
-----
* added `DsCaster` to support dumping the contents of data structures from the Ds extension
4.2.0
-----
@@ -20,9 +36,9 @@ CHANGELOG
* support for passing `\ReflectionClass` instances to the `Caster::castObject()`
method has been dropped, pass class names as strings instead
* the `Data::getRawData()` method has been removed
* the `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$context = null`
* the `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position.
* the `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$context = null`
* the `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$filter = 0`
argument and moves `$message = ''` argument at 4th position.
3.4.0
@@ -34,4 +50,4 @@ CHANGELOG
2.7.0
-----
* deprecated Cloner\Data::getLimitedClone(). Use withMaxDepth, withMaxItemsPerDepth or withRefHandles instead.
* deprecated `Cloner\Data::getLimitedClone()`. Use `withMaxDepth`, `withMaxItemsPerDepth` or `withRefHandles` instead.

View File

@@ -17,40 +17,42 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts Amqp related classes to array representation.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*
* @final since Symfony 4.4
*/
class AmqpCaster
{
private static $flags = array(
AMQP_DURABLE => 'AMQP_DURABLE',
AMQP_PASSIVE => 'AMQP_PASSIVE',
AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE',
AMQP_AUTODELETE => 'AMQP_AUTODELETE',
AMQP_INTERNAL => 'AMQP_INTERNAL',
AMQP_NOLOCAL => 'AMQP_NOLOCAL',
AMQP_AUTOACK => 'AMQP_AUTOACK',
AMQP_IFEMPTY => 'AMQP_IFEMPTY',
AMQP_IFUNUSED => 'AMQP_IFUNUSED',
AMQP_MANDATORY => 'AMQP_MANDATORY',
AMQP_IMMEDIATE => 'AMQP_IMMEDIATE',
AMQP_MULTIPLE => 'AMQP_MULTIPLE',
AMQP_NOWAIT => 'AMQP_NOWAIT',
AMQP_REQUEUE => 'AMQP_REQUEUE',
);
private const FLAGS = [
\AMQP_DURABLE => 'AMQP_DURABLE',
\AMQP_PASSIVE => 'AMQP_PASSIVE',
\AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE',
\AMQP_AUTODELETE => 'AMQP_AUTODELETE',
\AMQP_INTERNAL => 'AMQP_INTERNAL',
\AMQP_NOLOCAL => 'AMQP_NOLOCAL',
\AMQP_AUTOACK => 'AMQP_AUTOACK',
\AMQP_IFEMPTY => 'AMQP_IFEMPTY',
\AMQP_IFUNUSED => 'AMQP_IFUNUSED',
\AMQP_MANDATORY => 'AMQP_MANDATORY',
\AMQP_IMMEDIATE => 'AMQP_IMMEDIATE',
\AMQP_MULTIPLE => 'AMQP_MULTIPLE',
\AMQP_NOWAIT => 'AMQP_NOWAIT',
\AMQP_REQUEUE => 'AMQP_REQUEUE',
];
private static $exchangeTypes = array(
AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT',
AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT',
AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC',
AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS',
);
private const EXCHANGE_TYPES = [
\AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT',
\AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT',
\AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC',
\AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS',
];
public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$a += [
$prefix.'is_connected' => $c->isConnected(),
);
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPConnection\x00login"])) {
@@ -64,7 +66,7 @@ class AmqpCaster
$timeout = $c->getTimeout();
}
$a += array(
$a += [
$prefix.'is_connected' => $c->isConnected(),
$prefix.'login' => $c->getLogin(),
$prefix.'password' => $c->getPassword(),
@@ -72,7 +74,7 @@ class AmqpCaster
$prefix.'vhost' => $c->getVhost(),
$prefix.'port' => $c->getPort(),
$prefix.'read_timeout' => $timeout,
);
];
return $a;
}
@@ -81,21 +83,21 @@ class AmqpCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$a += [
$prefix.'is_connected' => $c->isConnected(),
$prefix.'channel_id' => $c->getChannelId(),
);
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPChannel\x00connection"])) {
return $a;
}
$a += array(
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'prefetch_size' => $c->getPrefetchSize(),
$prefix.'prefetch_count' => $c->getPrefetchCount(),
);
];
return $a;
}
@@ -104,21 +106,21 @@ class AmqpCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$a += [
$prefix.'flags' => self::extractFlags($c->getFlags()),
);
];
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPQueue\x00name"])) {
return $a;
}
$a += array(
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'arguments' => $c->getArguments(),
);
];
return $a;
}
@@ -127,11 +129,11 @@ class AmqpCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$a += [
$prefix.'flags' => self::extractFlags($c->getFlags()),
);
];
$type = isset(self::$exchangeTypes[$c->getType()]) ? new ConstStub(self::$exchangeTypes[$c->getType()], $c->getType()) : $c->getType();
$type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType();
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPExchange\x00name"])) {
@@ -140,13 +142,13 @@ class AmqpCaster
return $a;
}
$a += array(
$a += [
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'type' => $type,
$prefix.'arguments' => $c->getArguments(),
);
];
return $a;
}
@@ -165,10 +167,10 @@ class AmqpCaster
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$a += array($prefix.'body' => $c->getBody());
$a += [$prefix.'body' => $c->getBody()];
}
$a += array(
$a += [
$prefix.'delivery_tag' => $c->getDeliveryTag(),
$prefix.'is_redelivery' => $c->isRedelivery(),
$prefix.'exchange_name' => $c->getExchangeName(),
@@ -186,23 +188,23 @@ class AmqpCaster
$prefix.'type' => $c->getType(),
$prefix.'user_id' => $c->getUserId(),
$prefix.'app_id' => $c->getAppId(),
);
];
return $a;
}
private static function extractFlags($flags)
private static function extractFlags(int $flags): ConstStub
{
$flagsArray = array();
$flagsArray = [];
foreach (self::$flags as $value => $name) {
foreach (self::FLAGS as $value => $name) {
if ($flags & $value) {
$flagsArray[] = $name;
}
}
if (!$flagsArray) {
$flagsArray = array('AMQP_NOPARAM');
$flagsArray = ['AMQP_NOPARAM'];
}
return new ConstStub(implode('|', $flagsArray), $flags);

View File

@@ -20,15 +20,15 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class ArgsStub extends EnumStub
{
private static $parameters = array();
private static $parameters = [];
public function __construct(array $args, string $function, ?string $class)
{
list($variadic, $params) = self::getParameters($function, $class);
[$variadic, $params] = self::getParameters($function, $class);
$values = array();
$values = [];
foreach ($args as $k => $v) {
$values[$k] = !is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v;
$values[$k] = !\is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v;
}
if (null === $params) {
parent::__construct($values, false);
@@ -41,7 +41,7 @@ class ArgsStub extends EnumStub
$values[] = new EnumStub(array_splice($values, \count($params)), false);
$params[] = $variadic;
}
if (array('...') === $params) {
if (['...'] === $params) {
$this->dumpKeys = false;
$this->value = $values[0]->value;
} else {
@@ -49,7 +49,7 @@ class ArgsStub extends EnumStub
}
}
private static function getParameters($function, $class)
private static function getParameters(string $function, ?string $class): array
{
if (isset(self::$parameters[$k = $class.'::'.$function])) {
return self::$parameters[$k];
@@ -58,11 +58,11 @@ class ArgsStub extends EnumStub
try {
$r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function);
} catch (\ReflectionException $e) {
return array(null, null);
return [null, null];
}
$variadic = '...';
$params = array();
$params = [];
foreach ($r->getParameters() as $v) {
$k = '$'.$v->name;
if ($v->isPassedByReference()) {
@@ -75,6 +75,6 @@ class ArgsStub extends EnumStub
}
}
return self::$parameters[$k] = array($variadic, $params);
return self::$parameters[$k] = [$variadic, $params];
}
}

View File

@@ -22,60 +22,64 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class Caster
{
const EXCLUDE_VERBOSE = 1;
const EXCLUDE_VIRTUAL = 2;
const EXCLUDE_DYNAMIC = 4;
const EXCLUDE_PUBLIC = 8;
const EXCLUDE_PROTECTED = 16;
const EXCLUDE_PRIVATE = 32;
const EXCLUDE_NULL = 64;
const EXCLUDE_EMPTY = 128;
const EXCLUDE_NOT_IMPORTANT = 256;
const EXCLUDE_STRICT = 512;
public const EXCLUDE_VERBOSE = 1;
public const EXCLUDE_VIRTUAL = 2;
public const EXCLUDE_DYNAMIC = 4;
public const EXCLUDE_PUBLIC = 8;
public const EXCLUDE_PROTECTED = 16;
public const EXCLUDE_PRIVATE = 32;
public const EXCLUDE_NULL = 64;
public const EXCLUDE_EMPTY = 128;
public const EXCLUDE_NOT_IMPORTANT = 256;
public const EXCLUDE_STRICT = 512;
const PREFIX_VIRTUAL = "\0~\0";
const PREFIX_DYNAMIC = "\0+\0";
const PREFIX_PROTECTED = "\0*\0";
public const PREFIX_VIRTUAL = "\0~\0";
public const PREFIX_DYNAMIC = "\0+\0";
public const PREFIX_PROTECTED = "\0*\0";
/**
* Casts objects to arrays and adds the dynamic property prefix.
*
* @param object $obj The object to cast
* @param string $class The class of the object
* @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not
*
* @return array The array-cast of the object, with prefixed dynamic properties
*/
public static function castObject($obj, $class, $hasDebugInfo = false)
public static function castObject($obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array
{
if ($hasDebugInfo) {
$a = $obj->__debugInfo();
} elseif ($obj instanceof \Closure) {
$a = array();
} else {
$a = (array) $obj;
try {
$debugInfo = $obj->__debugInfo();
} catch (\Exception $e) {
// ignore failing __debugInfo()
$hasDebugInfo = false;
}
}
$a = $obj instanceof \Closure ? [] : (array) $obj;
if ($obj instanceof \__PHP_Incomplete_Class) {
return $a;
}
if ($a) {
static $publicProperties = array();
static $publicProperties = [];
$debugClass = $debugClass ?? get_debug_type($obj);
$i = 0;
$prefixedKeys = array();
$prefixedKeys = [];
foreach ($a as $k => $v) {
if (isset($k[0]) ? "\0" !== $k[0] : \PHP_VERSION_ID >= 70200) {
if (!isset($publicProperties[$class])) {
foreach (get_class_vars($class) as $prop => $v) {
$publicProperties[$class][$prop] = true;
foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) {
$publicProperties[$class][$prop->name] = true;
}
}
if (!isset($publicProperties[$class][$k])) {
$prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k;
}
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
$prefixedKeys[$i] = "\0".get_parent_class($class).'@anonymous'.strrchr($k, "\0");
} elseif ($debugClass !== $class && 1 === strpos($k, $class)) {
$prefixedKeys[$i] = "\0".$debugClass.strrchr($k, "\0");
}
++$i;
}
@@ -88,6 +92,20 @@ class Caster
}
}
if ($hasDebugInfo && \is_array($debugInfo)) {
foreach ($debugInfo as $k => $v) {
if (!isset($k[0]) || "\0" !== $k[0]) {
if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) {
continue;
}
$k = self::PREFIX_VIRTUAL.$k;
}
unset($a[$k]);
$a[$k] = $v;
}
}
return $a;
}
@@ -104,7 +122,7 @@ class Caster
*
* @return array The filtered array
*/
public static function filter(array $a, $filter, array $listedProperties = array(), &$count = 0)
public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0): array
{
$count = 0;
@@ -114,7 +132,7 @@ class Caster
if (null === $v) {
$type |= self::EXCLUDE_NULL & $filter;
$type |= self::EXCLUDE_EMPTY & $filter;
} elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || array() === $v) {
} elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) {
$type |= self::EXCLUDE_EMPTY & $filter;
}
if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) {
@@ -145,7 +163,7 @@ class Caster
return $a;
}
public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, $isNested)
public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array
{
if (isset($a['__PHP_Incomplete_Class_Name'])) {
$stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')';

View File

@@ -33,16 +33,16 @@ class ClassStub extends ConstStub
if ($callable instanceof \Closure) {
$r = new \ReflectionFunction($callable);
} elseif (\is_object($callable)) {
$r = array($callable, '__invoke');
$r = [$callable, '__invoke'];
} elseif (\is_array($callable)) {
$r = $callable;
} elseif (false !== $i = strpos($callable, '::')) {
$r = array(substr($callable, 0, $i), substr($callable, 2 + $i));
$r = [substr($callable, 0, $i), substr($callable, 2 + $i)];
} else {
$r = new \ReflectionFunction($callable);
}
} elseif (0 < $i = strpos($identifier, '::') ?: strpos($identifier, '->')) {
$r = array(substr($identifier, 0, $i), substr($identifier, 2 + $i));
$r = [substr($identifier, 0, $i), substr($identifier, 2 + $i)];
} else {
$r = new \ReflectionClass($identifier);
}
@@ -55,17 +55,17 @@ class ClassStub extends ConstStub
}
}
if (false !== strpos($identifier, "class@anonymous\0")) {
$this->value = $identifier = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
if (str_contains($identifier, "@anonymous\0")) {
$this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $identifier);
}
if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) {
$s = ReflectionCaster::castFunctionAbstract($r, array(), new Stub(), true);
$s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), true, Caster::EXCLUDE_VERBOSE);
$s = ReflectionCaster::getSignature($s);
if ('()' === substr($identifier, -2)) {
if (str_ends_with($identifier, '()')) {
$this->value = substr_replace($identifier, $s, -2);
} else {
$this->value .= $s;

View File

@@ -20,12 +20,15 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class ConstStub extends Stub
{
public function __construct(string $name, $value)
public function __construct(string $name, $value = null)
{
$this->class = $name;
$this->value = $value;
$this->value = 1 < \func_num_args() ? $value : $name;
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->value;

View File

@@ -28,6 +28,11 @@ class CutStub extends Stub
case 'object':
$this->type = self::TYPE_OBJECT;
$this->class = \get_class($value);
if ($value instanceof \Closure) {
ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE);
}
$this->cut = -1;
break;

View File

@@ -17,55 +17,57 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts DOM related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class DOMCaster
{
private static $errorCodes = array(
DOM_PHP_ERR => 'DOM_PHP_ERR',
DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR',
DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR',
DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR',
DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR',
DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR',
DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR',
DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR',
DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR',
DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR',
DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR',
DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR',
DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR',
DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR',
DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR',
DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR',
DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR',
);
private const ERROR_CODES = [
\DOM_PHP_ERR => 'DOM_PHP_ERR',
\DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR',
\DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR',
\DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR',
\DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR',
\DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR',
\DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR',
\DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR',
\DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR',
\DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR',
\DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR',
\DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR',
\DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR',
\DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR',
\DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR',
\DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR',
\DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR',
];
private static $nodeTypes = array(
XML_ELEMENT_NODE => 'XML_ELEMENT_NODE',
XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE',
XML_TEXT_NODE => 'XML_TEXT_NODE',
XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE',
XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE',
XML_ENTITY_NODE => 'XML_ENTITY_NODE',
XML_PI_NODE => 'XML_PI_NODE',
XML_COMMENT_NODE => 'XML_COMMENT_NODE',
XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE',
XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE',
XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE',
XML_NOTATION_NODE => 'XML_NOTATION_NODE',
XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE',
XML_DTD_NODE => 'XML_DTD_NODE',
XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE',
XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE',
XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE',
XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE',
);
private const NODE_TYPES = [
\XML_ELEMENT_NODE => 'XML_ELEMENT_NODE',
\XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE',
\XML_TEXT_NODE => 'XML_TEXT_NODE',
\XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE',
\XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE',
\XML_ENTITY_NODE => 'XML_ENTITY_NODE',
\XML_PI_NODE => 'XML_PI_NODE',
\XML_COMMENT_NODE => 'XML_COMMENT_NODE',
\XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE',
\XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE',
\XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE',
\XML_NOTATION_NODE => 'XML_NOTATION_NODE',
\XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE',
\XML_DTD_NODE => 'XML_DTD_NODE',
\XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE',
\XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE',
\XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE',
\XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE',
];
public static function castException(\DOMException $e, array $a, Stub $stub, $isNested)
{
$k = Caster::PREFIX_PROTECTED.'code';
if (isset($a[$k], self::$errorCodes[$a[$k]])) {
$a[$k] = new ConstStub(self::$errorCodes[$a[$k]], $a[$k]);
if (isset($a[$k], self::ERROR_CODES[$a[$k]])) {
$a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]);
}
return $a;
@@ -73,29 +75,29 @@ class DOMCaster
public static function castLength($dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'length' => $dom->length,
);
];
return $a;
}
public static function castImplementation($dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'Core' => '1.0',
Caster::PREFIX_VIRTUAL.'XML' => '2.0',
);
];
return $a;
}
public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$dom->nodeType], $dom->nodeType),
'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType),
'parentNode' => new CutStub($dom->parentNode),
'childNodes' => $dom->childNodes,
'firstChild' => new CutStub($dom->firstChild),
@@ -109,30 +111,30 @@ class DOMCaster
'localName' => $dom->localName,
'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI,
'textContent' => new CutStub($dom->textContent),
);
];
return $a;
}
public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$dom->nodeType], $dom->nodeType),
'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType),
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'namespaceURI' => $dom->namespaceURI,
'ownerDocument' => new CutStub($dom->ownerDocument),
'parentNode' => new CutStub($dom->parentNode),
);
];
return $a;
}
public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
$a += [
'doctype' => $dom->doctype,
'implementation' => $dom->implementation,
'documentElement' => new CutStub($dom->documentElement),
@@ -152,12 +154,12 @@ class DOMCaster
'preserveWhiteSpace' => $dom->preserveWhiteSpace,
'recover' => $dom->recover,
'substituteEntities' => $dom->substituteEntities,
);
];
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$formatOutput = $dom->formatOutput;
$dom->formatOutput = true;
$a += array(Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML());
$a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()];
$dom->formatOutput = $formatOutput;
}
@@ -166,136 +168,136 @@ class DOMCaster
public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'data' => $dom->data,
'length' => $dom->length,
);
];
return $a;
}
public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'name' => $dom->name,
'specified' => $dom->specified,
'value' => $dom->value,
'ownerElement' => $dom->ownerElement,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
];
return $a;
}
public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'tagName' => $dom->tagName,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
];
return $a;
}
public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'wholeText' => $dom->wholeText,
);
];
return $a;
}
public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'typeName' => $dom->typeName,
'typeNamespace' => $dom->typeNamespace,
);
];
return $a;
}
public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'severity' => $dom->severity,
'message' => $dom->message,
'type' => $dom->type,
'relatedException' => $dom->relatedException,
'related_data' => $dom->related_data,
'location' => $dom->location,
);
];
return $a;
}
public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'lineNumber' => $dom->lineNumber,
'columnNumber' => $dom->columnNumber,
'offset' => $dom->offset,
'relatedNode' => $dom->relatedNode,
'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri,
);
];
return $a;
}
public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'name' => $dom->name,
'entities' => $dom->entities,
'notations' => $dom->notations,
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'internalSubset' => $dom->internalSubset,
);
];
return $a;
}
public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
);
];
return $a;
}
public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'notationName' => $dom->notationName,
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'version' => $dom->version,
);
];
return $a;
}
public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'target' => $dom->target,
'data' => $dom->data,
);
];
return $a;
}
public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
'document' => $dom->document,
);
];
return $a;
}

View File

@@ -17,6 +17,8 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts DateTimeInterface related classes to array representation.
*
* @author Dany Maillard <danymaillard93b@gmail.com>
*
* @final since Symfony 4.4
*/
class DateCaster
{
@@ -33,7 +35,11 @@ class DateCaster
.($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '')
;
$a = array();
unset(
$a[Caster::PREFIX_DYNAMIC.'date'],
$a[Caster::PREFIX_DYNAMIC.'timezone'],
$a[Caster::PREFIX_DYNAMIC.'timezone_type']
);
$a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title);
$stub->class .= $d->format(' @U');
@@ -43,21 +49,22 @@ class DateCaster
public static function castInterval(\DateInterval $interval, array $a, Stub $stub, $isNested, $filter)
{
$now = new \DateTimeImmutable();
$now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
$numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp();
$title = number_format($numberOfSeconds, 0, '.', ' ').'s';
$i = array(Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title));
$i = [Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title)];
return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a;
}
private static function formatInterval(\DateInterval $i)
private static function formatInterval(\DateInterval $i): string
{
$format = '%R ';
if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) {
$i = date_diff($d = new \DateTime(), date_add(clone $d, $i)); // recalculate carry over points
$d = new \DateTimeImmutable('@0', new \DateTimeZone('UTC'));
$i = $d->diff($d->add($i)); // recalculate carry over points
$format .= 0 < $i->days ? '%ad ' : '';
} else {
$format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : '');
@@ -75,20 +82,20 @@ class DateCaster
$formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P');
$title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-'.$location['country_code']) : '';
$z = array(Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title));
$z = [Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title)];
return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a;
}
public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, $isNested, $filter)
{
$dates = array();
if (\PHP_VERSION_ID >= 70107) { // see https://bugs.php.net/bug.php?id=74639
$dates = [];
if (\PHP_VERSION_ID >= 70107) { // see https://bugs.php.net/74639
foreach (clone $p as $i => $d) {
if (self::PERIOD_LIMIT === $i) {
$now = new \DateTimeImmutable();
$now = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
$dates[] = sprintf('%s more', ($end = $p->getEndDate())
? ceil(($end->format('U.u') - $d->format('U.u')) / ($now->add($p->getDateInterval())->format('U.u') - $now->format('U.u')))
? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u')))
: $p->recurrences - $i
);
break;
@@ -98,24 +105,24 @@ class DateCaster
}
$period = sprintf(
'every %s, from %s (%s) %s',
'every %s, from %s%s %s',
self::formatInterval($p->getDateInterval()),
$p->include_start_date ? '[' : ']',
self::formatDateTime($p->getStartDate()),
$p->include_start_date ? 'included' : 'excluded',
($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end) : 'recurring '.$p->recurrences.' time/s'
($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s'
);
$p = array(Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates)));
$p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))];
return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a;
}
private static function formatDateTime(\DateTimeInterface $d, $extra = '')
private static function formatDateTime(\DateTimeInterface $d, string $extra = ''): string
{
return $d->format('Y-m-d H:i:'.self::formatSeconds($d->format('s'), $d->format('u')).$extra);
}
private static function formatSeconds($s, $us)
private static function formatSeconds(string $s, string $us): string
{
return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us));
}

View File

@@ -20,13 +20,15 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts Doctrine related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class DoctrineCaster
{
public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested)
{
foreach (array('__cloner__', '__initializer__') as $k) {
if (array_key_exists($k, $a)) {
foreach (['__cloner__', '__initializer__'] as $k) {
if (\array_key_exists($k, $a)) {
unset($a[$k]);
++$stub->cut;
}
@@ -37,8 +39,8 @@ class DoctrineCaster
public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested)
{
foreach (array('_entityPersister', '_identifier') as $k) {
if (array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) {
foreach (['_entityPersister', '_identifier'] as $k) {
if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) {
unset($a[$k]);
++$stub->cut;
}
@@ -49,8 +51,8 @@ class DoctrineCaster
public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested)
{
foreach (array('snapshot', 'association', 'typeClass') as $k) {
if (array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) {
foreach (['snapshot', 'association', 'typeClass'] as $k) {
if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) {
$a[$k] = new CutStub($a[$k]);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Ds\Collection;
use Ds\Map;
use Ds\Pair;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Casts Ds extension classes to array representation.
*
* @author Jáchym Toušek <enumag@gmail.com>
*
* @final since Symfony 4.4
*/
class DsCaster
{
public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array
{
$a[Caster::PREFIX_VIRTUAL.'count'] = $c->count();
$a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity();
if (!$c instanceof Map) {
$a += $c->toArray();
}
return $a;
}
public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($c as $k => $v) {
$a[] = new DsPairStub($k, $v);
}
return $a;
}
public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($c->toArray() as $k => $v) {
$a[Caster::PREFIX_VIRTUAL.$k] = $v;
}
return $a;
}
public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array
{
if ($isNested) {
$stub->class = Pair::class;
$stub->value = null;
$stub->handle = 0;
$a = $c->value;
}
return $a;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DsPairStub extends Stub
{
public function __construct($key, $value)
{
$this->value = [
Caster::PREFIX_VIRTUAL.'key' => $key,
Caster::PREFIX_VIRTUAL.'value' => $value,
];
}
}

View File

@@ -11,7 +11,7 @@
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
@@ -19,30 +19,32 @@ use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
* Casts common Exception classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ExceptionCaster
{
public static $srcContext = 1;
public static $traceArgs = true;
public static $errorTypes = array(
E_DEPRECATED => 'E_DEPRECATED',
E_USER_DEPRECATED => 'E_USER_DEPRECATED',
E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
E_ERROR => 'E_ERROR',
E_WARNING => 'E_WARNING',
E_PARSE => 'E_PARSE',
E_NOTICE => 'E_NOTICE',
E_CORE_ERROR => 'E_CORE_ERROR',
E_CORE_WARNING => 'E_CORE_WARNING',
E_COMPILE_ERROR => 'E_COMPILE_ERROR',
E_COMPILE_WARNING => 'E_COMPILE_WARNING',
E_USER_ERROR => 'E_USER_ERROR',
E_USER_WARNING => 'E_USER_WARNING',
E_USER_NOTICE => 'E_USER_NOTICE',
E_STRICT => 'E_STRICT',
);
public static $errorTypes = [
\E_DEPRECATED => 'E_DEPRECATED',
\E_USER_DEPRECATED => 'E_USER_DEPRECATED',
\E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
\E_ERROR => 'E_ERROR',
\E_WARNING => 'E_WARNING',
\E_PARSE => 'E_PARSE',
\E_NOTICE => 'E_NOTICE',
\E_CORE_ERROR => 'E_CORE_ERROR',
\E_CORE_WARNING => 'E_CORE_WARNING',
\E_COMPILE_ERROR => 'E_COMPILE_ERROR',
\E_COMPILE_WARNING => 'E_COMPILE_WARNING',
\E_USER_ERROR => 'E_USER_ERROR',
\E_USER_WARNING => 'E_USER_WARNING',
\E_USER_NOTICE => 'E_USER_NOTICE',
\E_STRICT => 'E_STRICT',
];
private static $framesCache = array();
private static $framesCache = [];
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
{
@@ -71,8 +73,7 @@ class ExceptionCaster
if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) {
$b = (array) $a[$xPrefix.'previous'];
$class = \get_class($a[$xPrefix.'previous']);
$class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
$class = get_debug_type($a[$xPrefix.'previous']);
self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']);
$a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value));
}
@@ -94,10 +95,10 @@ class ExceptionCaster
$a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
}
$trace = array(array(
$trace = [[
'file' => $a[$sPrefix.'file'],
'line' => $a[$sPrefix.'line'],
));
]];
if (isset($a[$sPrefix.'trace'])) {
$trace = array_merge($trace, $a[$sPrefix.'trace']);
@@ -119,16 +120,16 @@ class ExceptionCaster
$frames = $trace->value;
$prefix = Caster::PREFIX_VIRTUAL;
$a = array();
$a = [];
$j = \count($frames);
if (0 > $i = $trace->sliceOffset) {
$i = max(0, $j + $i);
}
if (!isset($trace->value[$i])) {
return array();
return [];
}
$lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '';
$frames[] = array('function' => '');
$frames[] = ['function' => ''];
$collapse = false;
for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
@@ -136,19 +137,19 @@ class ExceptionCaster
$call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'] : '???';
$frame = new FrameStub(
array(
'object' => isset($f['object']) ? $f['object'] : null,
'class' => isset($f['class']) ? $f['class'] : null,
'type' => isset($f['type']) ? $f['type'] : null,
'function' => isset($f['function']) ? $f['function'] : null,
) + $frames[$i - 1],
[
'object' => $f['object'] ?? null,
'class' => $f['class'] ?? null,
'type' => $f['type'] ?? null,
'function' => $f['function'] ?? null,
] + $frames[$i - 1],
false,
true
);
$f = self::castFrameStub($frame, array(), $frame, true);
$f = self::castFrameStub($frame, [], $frame, true);
if (isset($f[$prefix.'src'])) {
foreach ($f[$prefix.'src']->value as $label => $frame) {
if (0 === strpos($label, "\0~collapse=0")) {
if (str_starts_with($label, "\0~collapse=0")) {
if ($collapse) {
$label = substr_replace($label, '1', 11, 1);
} else {
@@ -159,7 +160,7 @@ class ExceptionCaster
}
$f = $frames[$i - 1];
if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) {
$frame->value['arguments'] = new ArgsStub($f['args'], isset($f['function']) ? $f['function'] : null, isset($f['class']) ? $f['class'] : null);
$frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null);
}
} elseif ('???' !== $lastCall) {
$label = new ClassStub($lastCall);
@@ -204,44 +205,49 @@ class ExceptionCaster
$f['file'] = substr($f['file'], 0, -\strlen($match[0]));
$f['line'] = (int) $match[1];
}
$caller = isset($f['function']) ? sprintf('in %s() on line %d', (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'], $f['line']) : null;
$src = $f['line'];
$srcKey = $f['file'];
$ellipsis = new LinkStub($srcKey, 0);
$srcAttr = 'collapse='.(int) $ellipsis->inVendor;
$ellipsisTail = isset($ellipsis->attr['ellipsis-tail']) ? $ellipsis->attr['ellipsis-tail'] : 0;
$ellipsis = isset($ellipsis->attr['ellipsis']) ? $ellipsis->attr['ellipsis'] : 0;
$ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0;
$ellipsis = $ellipsis->attr['ellipsis'] ?? 0;
if (file_exists($f['file']) && 0 <= self::$srcContext) {
if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) {
$template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class']));
$ellipsis = 0;
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
$templateInfo = $template->getDebugInfo();
if (isset($templateInfo[$f['line']])) {
if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) {
$templatePath = null;
}
if ($templateSrc) {
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath);
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
$template = null;
if (isset($f['object'])) {
$template = $f['object'];
} elseif ((new \ReflectionClass($f['class']))->isInstantiable()) {
$template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class']));
}
if (null !== $template) {
$ellipsis = 0;
$templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : '');
$templateInfo = $template->getDebugInfo();
if (isset($templateInfo[$f['line']])) {
if (!method_exists($template, 'getSourceContext') || !file_exists($templatePath = $template->getSourceContext()->getPath())) {
$templatePath = null;
}
if ($templateSrc) {
$src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f);
$srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']];
}
}
}
}
if ($srcKey == $f['file']) {
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f);
$srcKey .= ':'.$f['line'];
if ($ellipsis) {
$ellipsis += 1 + \strlen($f['line']);
}
}
$srcAttr .= '&separator= ';
$srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']);
} else {
$srcAttr .= '&separator=:';
}
$srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : '';
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(["\0~$srcAttr\0$srcKey" => $src]);
}
}
@@ -261,13 +267,13 @@ class ExceptionCaster
return $a;
}
private static function filterExceptionArray($xClass, array $a, $xPrefix, $filter)
private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array
{
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
$trace = [];
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) {
@@ -281,9 +287,9 @@ class ExceptionCaster
}
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
if (isset($a[Caster::PREFIX_PROTECTED.'message']) && false !== strpos($a[Caster::PREFIX_PROTECTED.'message'], "class@anonymous\0")) {
$a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) {
$a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) {
return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0];
}, $a[Caster::PREFIX_PROTECTED.'message']);
}
@@ -294,28 +300,53 @@ class ExceptionCaster
return $a;
}
private static function traceUnshift(&$trace, $class, $file, $line)
private static function traceUnshift(array &$trace, ?string $class, string $file, int $line): void
{
if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) {
return;
}
array_unshift($trace, array(
array_unshift($trace, [
'function' => $class ? 'new '.$class : null,
'file' => $file,
'line' => $line,
));
]);
}
private static function extractSource($srcLines, $line, $srcContext, $title, $lang, $file = null)
private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub
{
$srcLines = explode("\n", $srcLines);
$src = array();
$src = [];
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
$src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n";
$src[] = ($srcLines[$i] ?? '')."\n";
}
if ($frame['function'] ?? false) {
$stub = new CutStub(new \stdClass());
$stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function'];
$stub->type = Stub::TYPE_OBJECT;
$stub->attr['cut_hash'] = true;
$stub->attr['file'] = $frame['file'];
$stub->attr['line'] = $frame['line'];
try {
$caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']);
$stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE));
if ($f = $caller->getFileName()) {
$stub->attr['file'] = $f;
$stub->attr['line'] = $caller->getStartLine();
}
} catch (\ReflectionException $e) {
// ignore fake class/function
}
$srcLines = ["\0~separator=\0" => $stub];
} else {
$stub = null;
$srcLines = [];
}
$srcLines = array();
$ltrim = 0;
do {
$pad = null;
@@ -342,7 +373,7 @@ class ExceptionCaster
if ($i !== $srcContext) {
$c = new ConstStub('default', $c);
} else {
$c = new ConstStub($c, $title);
$c = new ConstStub($c, $stub ? 'in '.$stub->class : '');
if (null !== $file) {
$c->attr['file'] = $file;
$c->attr['line'] = $line;

View File

@@ -18,6 +18,8 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*
* @author Hamza Amrouche <hamza.simperfit@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class GmpCaster
{

View File

@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Imagine\Image\ImageInterface;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
final class ImagineCaster
{
public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested): array
{
$imgData = $c->get('png');
if (\strlen($imgData) > 1 * 1000 * 1000) {
$a += [
Caster::PREFIX_VIRTUAL.'image' => new ConstStub($c->getSize()),
];
} else {
$a += [
Caster::PREFIX_VIRTUAL.'image' => new ImgStub($imgData, 'image/png', $c->getSize()),
];
}
return $a;
}
}

View File

@@ -0,0 +1,26 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class ImgStub extends ConstStub
{
public function __construct(string $data, string $contentType, string $size)
{
$this->value = '';
$this->attr['img-data'] = $data;
$this->attr['img-size'] = $size;
$this->attr['content-type'] = $contentType;
}
}

View File

@@ -16,25 +16,27 @@ use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
* @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
*
* @final since Symfony 4.4
*/
class IntlCaster
{
public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
);
];
return self::castError($c, $a);
}
public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
);
];
if ($filter & Caster::EXCLUDE_VERBOSE) {
$stub->cut += 3;
@@ -42,9 +44,9 @@ class IntlCaster
return self::castError($c, $a);
}
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'attributes' => new EnumStub(
array(
[
'PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY),
'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED),
'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN),
@@ -65,10 +67,10 @@ class IntlCaster
'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS),
'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS),
'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE),
)
]
),
Caster::PREFIX_VIRTUAL.'text_attributes' => new EnumStub(
array(
[
'POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX),
'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX),
'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX),
@@ -77,10 +79,10 @@ class IntlCaster
'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE),
'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET),
'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS),
)
]
),
Caster::PREFIX_VIRTUAL.'symbols' => new EnumStub(
array(
[
'DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL),
'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL),
'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL),
@@ -99,25 +101,25 @@ class IntlCaster
'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL),
'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL),
'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL),
)
),
);
]
),
];
return self::castError($c, $a);
}
public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(),
Caster::PREFIX_VIRTUAL.'id' => $c->getID(),
Caster::PREFIX_VIRTUAL.'raw_offset' => $c->getRawOffset(),
);
];
if ($c->useDaylightTime()) {
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'dst_savings' => $c->getDSTSavings(),
);
];
}
return self::castError($c, $a);
@@ -125,25 +127,24 @@ class IntlCaster
public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'type' => $c->getType(),
Caster::PREFIX_VIRTUAL.'first_day_of_week' => $c->getFirstDayOfWeek(),
Caster::PREFIX_VIRTUAL.'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(),
Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(),
Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(),
Caster::PREFIX_VIRTUAL.'time' => $c->getTime(),
Caster::PREFIX_VIRTUAL.'type' => $c->getType(),
Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(),
Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(),
Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(),
);
];
return self::castError($c, $a);
}
public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(),
Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(),
Caster::PREFIX_VIRTUAL.'calendar' => $c->getCalendar(),
@@ -152,7 +153,7 @@ class IntlCaster
Caster::PREFIX_VIRTUAL.'date_type' => $c->getDateType(),
Caster::PREFIX_VIRTUAL.'calendar_object' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(),
Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(),
);
];
return self::castError($c, $a);
}
@@ -160,10 +161,10 @@ class IntlCaster
private static function castError($c, array $a): array
{
if ($errorCode = $c->getErrorCode()) {
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'error_code' => $errorCode,
Caster::PREFIX_VIRTUAL.'error_message' => $c->getErrorMessage(),
);
];
}
return $a;

View File

@@ -23,7 +23,7 @@ class LinkStub extends ConstStub
private static $vendorRoots;
private static $composerRoots;
public function __construct($label, int $line = 0, $href = null)
public function __construct(string $label, int $line = 0, string $href = null)
{
$this->value = $label;
@@ -33,12 +33,12 @@ class LinkStub extends ConstStub
if (!\is_string($href)) {
return;
}
if (0 === strpos($href, 'file://')) {
if (str_starts_with($href, 'file://')) {
if ($href === $label) {
$label = substr($label, 7);
}
$href = substr($href, 7);
} elseif (false !== strpos($href, '://')) {
} elseif (str_contains($href, '://')) {
$this->attr['href'] = $href;
return;
@@ -63,15 +63,15 @@ class LinkStub extends ConstStub
}
}
private function getComposerRoot($file, &$inVendor)
private function getComposerRoot(string $file, bool &$inVendor)
{
if (null === self::$vendorRoots) {
self::$vendorRoots = array();
self::$vendorRoots = [];
foreach (get_declared_classes() as $class) {
if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) {
if ('C' === $class[0] && str_starts_with($class, 'ComposerAutoloaderInit')) {
$r = new \ReflectionClass($class);
$v = \dirname(\dirname($r->getFileName()));
$v = \dirname($r->getFileName(), 2);
if (file_exists($v.'/composer/installed.json')) {
self::$vendorRoots[] = $v.\DIRECTORY_SEPARATOR;
}
@@ -85,7 +85,7 @@ class LinkStub extends ConstStub
}
foreach (self::$vendorRoots as $root) {
if ($inVendor = 0 === strpos($file, $root)) {
if ($inVendor = str_starts_with($file, $root)) {
return $root;
}
}

View File

@@ -15,6 +15,8 @@ use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
*
* @final since Symfony 4.4
*/
class MemcachedCaster
{
@@ -23,22 +25,22 @@ class MemcachedCaster
public static function castMemcached(\Memcached $c, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(),
Caster::PREFIX_VIRTUAL.'options' => new EnumStub(
self::getNonDefaultOptions($c)
),
);
];
return $a;
}
private static function getNonDefaultOptions(\Memcached $c)
private static function getNonDefaultOptions(\Memcached $c): array
{
self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions();
self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
$nonDefaultOptions = array();
$nonDefaultOptions = [];
foreach (self::$optionConstants as $constantKey => $value) {
if (self::$defaultOptions[$constantKey] !== $option = $c->getOption($value)) {
$nonDefaultOptions[$constantKey] = $option;
@@ -48,12 +50,12 @@ class MemcachedCaster
return $nonDefaultOptions;
}
private static function discoverDefaultOptions()
private static function discoverDefaultOptions(): array
{
$defaultMemcached = new \Memcached();
$defaultMemcached->addServer('127.0.0.1', 11211);
$defaultOptions = array();
$defaultOptions = [];
self::$optionConstants = self::$optionConstants ?? self::getOptionConstants();
foreach (self::$optionConstants as $constantKey => $value) {
@@ -63,13 +65,13 @@ class MemcachedCaster
return $defaultOptions;
}
private static function getOptionConstants()
private static function getOptionConstants(): array
{
$reflectedMemcached = new \ReflectionClass(\Memcached::class);
$optionConstants = array();
$optionConstants = [];
foreach ($reflectedMemcached->getConstants() as $constantKey => $value) {
if (0 === strpos($constantKey, 'OPT_')) {
if (str_starts_with($constantKey, 'OPT_')) {
$optionConstants[$constantKey] = $value;
}
}

View File

@@ -0,0 +1,33 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @internal
*/
final class MysqliCaster
{
public static function castMysqliDriver(\mysqli_driver $c, array $a, Stub $stub, bool $isNested): array
{
foreach ($a as $k => $v) {
if (isset($c->$k)) {
$a[$k] = $c->$k;
}
}
return $a;
}
}

View File

@@ -17,56 +17,58 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts PDO related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class PdoCaster
{
private static $pdoAttributes = array(
'CASE' => array(
private const PDO_ATTRIBUTES = [
'CASE' => [
\PDO::CASE_LOWER => 'LOWER',
\PDO::CASE_NATURAL => 'NATURAL',
\PDO::CASE_UPPER => 'UPPER',
),
'ERRMODE' => array(
],
'ERRMODE' => [
\PDO::ERRMODE_SILENT => 'SILENT',
\PDO::ERRMODE_WARNING => 'WARNING',
\PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
),
],
'TIMEOUT',
'PREFETCH',
'AUTOCOMMIT',
'PERSISTENT',
'DRIVER_NAME',
'SERVER_INFO',
'ORACLE_NULLS' => array(
'ORACLE_NULLS' => [
\PDO::NULL_NATURAL => 'NATURAL',
\PDO::NULL_EMPTY_STRING => 'EMPTY_STRING',
\PDO::NULL_TO_STRING => 'TO_STRING',
),
],
'CLIENT_VERSION',
'SERVER_VERSION',
'STATEMENT_CLASS',
'EMULATE_PREPARES',
'CONNECTION_STATUS',
'STRINGIFY_FETCHES',
'DEFAULT_FETCH_MODE' => array(
'DEFAULT_FETCH_MODE' => [
\PDO::FETCH_ASSOC => 'ASSOC',
\PDO::FETCH_BOTH => 'BOTH',
\PDO::FETCH_LAZY => 'LAZY',
\PDO::FETCH_NUM => 'NUM',
\PDO::FETCH_OBJ => 'OBJ',
),
);
],
];
public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
{
$attr = array();
$attr = [];
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
foreach (self::$pdoAttributes as $k => $v) {
foreach (self::PDO_ATTRIBUTES as $k => $v) {
if (!isset($k[0])) {
$k = $v;
$v = array();
$v = [];
}
try {
@@ -85,11 +87,11 @@ class PdoCaster
}
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$a += [
$prefix.'inTransaction' => method_exists($c, 'inTransaction'),
$prefix.'errorInfo' => $c->errorInfo(),
$prefix.'attributes' => new EnumStub($attr),
);
];
if ($a[$prefix.'inTransaction']) {
$a[$prefix.'inTransaction'] = $c->inTransaction();

View File

@@ -17,10 +17,12 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts pqsql resources to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class PgSqlCaster
{
private static $paramCodes = array(
private const PARAM_CODES = [
'server_encoding',
'client_encoding',
'is_superuser',
@@ -31,41 +33,41 @@ class PgSqlCaster
'integer_datetimes',
'application_name',
'standard_conforming_strings',
);
];
private static $transactionStatus = array(
PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE',
PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE',
PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS',
PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR',
PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN',
);
private const TRANSACTION_STATUS = [
\PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE',
\PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE',
\PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS',
\PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR',
\PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN',
];
private static $resultStatus = array(
PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY',
PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK',
PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK',
PGSQL_COPY_OUT => 'PGSQL_COPY_OUT',
PGSQL_COPY_IN => 'PGSQL_COPY_IN',
PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE',
PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR',
PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR',
);
private const RESULT_STATUS = [
\PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY',
\PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK',
\PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK',
\PGSQL_COPY_OUT => 'PGSQL_COPY_OUT',
\PGSQL_COPY_IN => 'PGSQL_COPY_IN',
\PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE',
\PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR',
\PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR',
];
private static $diagCodes = array(
'severity' => PGSQL_DIAG_SEVERITY,
'sqlstate' => PGSQL_DIAG_SQLSTATE,
'message' => PGSQL_DIAG_MESSAGE_PRIMARY,
'detail' => PGSQL_DIAG_MESSAGE_DETAIL,
'hint' => PGSQL_DIAG_MESSAGE_HINT,
'statement position' => PGSQL_DIAG_STATEMENT_POSITION,
'internal position' => PGSQL_DIAG_INTERNAL_POSITION,
'internal query' => PGSQL_DIAG_INTERNAL_QUERY,
'context' => PGSQL_DIAG_CONTEXT,
'file' => PGSQL_DIAG_SOURCE_FILE,
'line' => PGSQL_DIAG_SOURCE_LINE,
'function' => PGSQL_DIAG_SOURCE_FUNCTION,
);
private const DIAG_CODES = [
'severity' => \PGSQL_DIAG_SEVERITY,
'sqlstate' => \PGSQL_DIAG_SQLSTATE,
'message' => \PGSQL_DIAG_MESSAGE_PRIMARY,
'detail' => \PGSQL_DIAG_MESSAGE_DETAIL,
'hint' => \PGSQL_DIAG_MESSAGE_HINT,
'statement position' => \PGSQL_DIAG_STATEMENT_POSITION,
'internal position' => \PGSQL_DIAG_INTERNAL_POSITION,
'internal query' => \PGSQL_DIAG_INTERNAL_QUERY,
'context' => \PGSQL_DIAG_CONTEXT,
'file' => \PGSQL_DIAG_SOURCE_FILE,
'line' => \PGSQL_DIAG_SOURCE_LINE,
'function' => \PGSQL_DIAG_SOURCE_FUNCTION,
];
public static function castLargeObject($lo, array $a, Stub $stub, $isNested)
{
@@ -77,12 +79,12 @@ class PgSqlCaster
public static function castLink($link, array $a, Stub $stub, $isNested)
{
$a['status'] = pg_connection_status($link);
$a['status'] = new ConstStub(PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']);
$a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']);
$a['busy'] = pg_connection_busy($link);
$a['transaction'] = pg_transaction_status($link);
if (isset(self::$transactionStatus[$a['transaction']])) {
$a['transaction'] = new ConstStub(self::$transactionStatus[$a['transaction']], $a['transaction']);
if (isset(self::TRANSACTION_STATUS[$a['transaction']])) {
$a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']);
}
$a['pid'] = pg_get_pid($link);
@@ -94,7 +96,7 @@ class PgSqlCaster
$a['options'] = pg_options($link);
$a['version'] = pg_version($link);
foreach (self::$paramCodes as $v) {
foreach (self::PARAM_CODES as $v) {
if (false !== $s = pg_parameter_status($link, $v)) {
$a['param'][$v] = $s;
}
@@ -110,13 +112,13 @@ class PgSqlCaster
{
$a['num rows'] = pg_num_rows($result);
$a['status'] = pg_result_status($result);
if (isset(self::$resultStatus[$a['status']])) {
$a['status'] = new ConstStub(self::$resultStatus[$a['status']], $a['status']);
if (isset(self::RESULT_STATUS[$a['status']])) {
$a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']);
}
$a['command-completion tag'] = pg_result_status($result, PGSQL_STATUS_STRING);
$a['command-completion tag'] = pg_result_status($result, \PGSQL_STATUS_STRING);
if (-1 === $a['num rows']) {
foreach (self::$diagCodes as $k => $v) {
foreach (self::DIAG_CODES as $k => $v) {
$a['error'][$k] = pg_result_error_field($result, $v);
}
}
@@ -127,14 +129,14 @@ class PgSqlCaster
$fields = pg_num_fields($result);
for ($i = 0; $i < $fields; ++$i) {
$field = array(
$field = [
'name' => pg_field_name($result, $i),
'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)),
'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)),
'nullable' => (bool) pg_field_is_null($result, $i),
'storage' => pg_field_size($result, $i).' bytes',
'display' => pg_field_prtlen($result, $i).' chars',
);
];
if (' (OID: )' === $field['table']) {
$field['table'] = null;
}

View File

@@ -16,12 +16,14 @@ use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ProxyManagerCaster
{
public static function castProxy(ProxyInterface $c, array $a, Stub $stub, $isNested)
{
if ($parent = \get_parent_class($c)) {
if ($parent = get_parent_class($c)) {
$stub->class .= ' - '.$parent;
}
$stub->class .= '@proxy';

View File

@@ -17,69 +17,71 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts Redis class from ext-redis to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class RedisCaster
{
private static $serializer = array(
private const SERIALIZERS = [
\Redis::SERIALIZER_NONE => 'NONE',
\Redis::SERIALIZER_PHP => 'PHP',
2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY
);
];
private static $mode = array(
private const MODES = [
\Redis::ATOMIC => 'ATOMIC',
\Redis::MULTI => 'MULTI',
\Redis::PIPELINE => 'PIPELINE',
);
];
private static $compression = array(
private const COMPRESSION_MODES = [
0 => 'NONE', // Redis::COMPRESSION_NONE
1 => 'LZF', // Redis::COMPRESSION_LZF
);
];
private static $failover = array(
private const FAILOVER_OPTIONS = [
\RedisCluster::FAILOVER_NONE => 'NONE',
\RedisCluster::FAILOVER_ERROR => 'ERROR',
\RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE',
\RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES',
);
];
public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if (!$connected = $c->isConnected()) {
return $a + array(
return $a + [
$prefix.'isConnected' => $connected,
);
];
}
$mode = $c->getMode();
return $a + array(
return $a + [
$prefix.'isConnected' => $connected,
$prefix.'host' => $c->getHost(),
$prefix.'port' => $c->getPort(),
$prefix.'auth' => $c->getAuth(),
$prefix.'mode' => isset(self::$mode[$mode]) ? new ConstStub(self::$mode[$mode], $mode) : $mode,
$prefix.'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode,
$prefix.'dbNum' => $c->getDbNum(),
$prefix.'timeout' => $c->getTimeout(),
$prefix.'lastError' => $c->getLastError(),
$prefix.'persistentId' => $c->getPersistentID(),
$prefix.'options' => self::getRedisOptions($c),
);
];
}
public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a + array(
return $a + [
$prefix.'hosts' => $c->_hosts(),
$prefix.'function' => ClassStub::wrapCallable($c->_function()),
$prefix.'lastError' => $c->getLastError(),
$prefix.'options' => self::getRedisOptions($c),
);
];
}
public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, $isNested)
@@ -87,15 +89,15 @@ class RedisCaster
$prefix = Caster::PREFIX_VIRTUAL;
$failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER);
$a += array(
$a += [
$prefix.'_masters' => $c->_masters(),
$prefix.'_redir' => $c->_redir(),
$prefix.'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()),
$prefix.'lastError' => $c->getLastError(),
$prefix.'options' => self::getRedisOptions($c, array(
'SLAVE_FAILOVER' => isset(self::$failover[$failover]) ? new ConstStub(self::$failover[$failover], $failover) : $failover,
)),
);
$prefix.'options' => self::getRedisOptions($c, [
'SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover,
]),
];
return $a;
}
@@ -103,28 +105,28 @@ class RedisCaster
/**
* @param \Redis|\RedisArray|\RedisCluster $redis
*/
private static function getRedisOptions($redis, array $options = array()): EnumStub
private static function getRedisOptions($redis, array $options = []): EnumStub
{
$serializer = $redis->getOption(\Redis::OPT_SERIALIZER);
if (\is_array($serializer)) {
foreach ($serializer as &$v) {
if (isset(self::$serializer[$v])) {
$v = new ConstStub(self::$serializer[$v], $v);
if (isset(self::SERIALIZERS[$v])) {
$v = new ConstStub(self::SERIALIZERS[$v], $v);
}
}
} elseif (isset(self::$serializer[$serializer])) {
$serializer = new ConstStub(self::$serializer[$serializer], $serializer);
} elseif (isset(self::SERIALIZERS[$serializer])) {
$serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer);
}
$compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0;
if (\is_array($compression)) {
foreach ($compression as &$v) {
if (isset(self::$compression[$v])) {
$v = new ConstStub(self::$compression[$v], $v);
if (isset(self::COMPRESSION_MODES[$v])) {
$v = new ConstStub(self::COMPRESSION_MODES[$v], $v);
}
}
} elseif (isset(self::$compression[$compression])) {
$compression = new ConstStub(self::$compression[$compression], $compression);
} elseif (isset(self::COMPRESSION_MODES[$compression])) {
$compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression);
}
$retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0;
@@ -136,14 +138,14 @@ class RedisCaster
$retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry);
}
$options += array(
$options += [
'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0,
'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT),
'COMPRESSION' => $compression,
'SERIALIZER' => $serializer,
'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX),
'SCAN' => $retry,
);
];
return new EnumStub($options);
}

View File

@@ -17,10 +17,14 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts Reflector related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ReflectionCaster
{
private static $extraMap = array(
public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo'];
private const EXTRA_MAP = [
'docComment' => 'getDocComment',
'extension' => 'getExtensionName',
'isDisabled' => 'isDisabled',
@@ -29,7 +33,7 @@ class ReflectionCaster
'isUserDefined' => 'isUserDefined',
'isGenerator' => 'isGenerator',
'isVariadic' => 'isVariadic',
);
];
public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $filter = 0)
{
@@ -38,7 +42,7 @@ class ReflectionCaster
$a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter);
if (false === strpos($c->name, '{closure}')) {
if (!str_contains($c->name, '{closure}')) {
$stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name;
unset($a[$prefix.'class']);
}
@@ -46,26 +50,20 @@ class ReflectionCaster
$stub->class .= self::getSignature($a);
if ($f = $c->getFileName()) {
$stub->attr['file'] = $f;
$stub->attr['line'] = $c->getStartLine();
}
unset($a[$prefix.'parameters']);
if ($filter & Caster::EXCLUDE_VERBOSE) {
$stub->cut += ($c->getFileName() ? 2 : 0) + \count($a);
return array();
return [];
}
if (isset($a[$prefix.'parameters'])) {
foreach ($a[$prefix.'parameters']->value as &$v) {
$param = $v;
$v = new EnumStub(array());
foreach (static::castParameter($param, array(), $stub, true) as $k => $param) {
if ("\0" === $k[0]) {
$v->value[substr($k, 3)] = $param;
}
}
unset($v->value['position'], $v->value['isVariadic'], $v->value['byReference'], $v);
}
}
if ($f = $c->getFileName()) {
if ($f) {
$a[$prefix.'file'] = new LinkStub($f, $c->getStartLine());
$a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine();
}
@@ -73,12 +71,15 @@ class ReflectionCaster
return $a;
}
public static function unsetClosureFileInfo(\Closure $c, array $a)
{
unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']);
return $a;
}
public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested)
{
if (!class_exists('ReflectionGenerator', false)) {
return $a;
}
// Cannot create ReflectionGenerator based on a terminated Generator
try {
$reflectionGenerator = new \ReflectionGenerator($c);
@@ -95,11 +96,20 @@ class ReflectionCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$prefix.'name' => $c->getName(),
$prefix.'allowsNull' => $c->allowsNull(),
$prefix.'isBuiltin' => $c->isBuiltin(),
);
if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) {
$a += [
$prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c,
$prefix.'allowsNull' => $c->allowsNull(),
$prefix.'isBuiltin' => $c->isBuiltin(),
];
} elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) {
$a[$prefix.'allowsNull'] = $c->allowsNull();
self::addMap($a, $c, [
'types' => 'getTypes',
]);
} else {
$a[$prefix.'allowsNull'] = $c->allowsNull();
}
return $a;
}
@@ -112,28 +122,26 @@ class ReflectionCaster
$a[$prefix.'this'] = new CutStub($c->getThis());
}
$function = $c->getFunction();
$frame = array(
'class' => isset($function->class) ? $function->class : null,
$frame = [
'class' => $function->class ?? null,
'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null,
'function' => $function->name,
'file' => $c->getExecutingFile(),
'line' => $c->getExecutingLine(),
);
if ($trace = $c->getTrace(DEBUG_BACKTRACE_IGNORE_ARGS)) {
];
if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) {
$function = new \ReflectionGenerator($c->getExecutingGenerator());
array_unshift($trace, array(
array_unshift($trace, [
'function' => 'yield',
'file' => $function->getExecutingFile(),
'line' => $function->getExecutingLine() - 1,
));
'line' => $function->getExecutingLine() - (int) (\PHP_VERSION_ID < 80100),
]);
$trace[] = $frame;
$a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1);
} else {
$function = new FrameStub($frame, false, true);
$function = ExceptionCaster::castFrameStub($function, array(), $function, true);
$a[$prefix.'executing'] = new EnumStub(array(
"\0~separator= \0".$frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'],
));
$function = ExceptionCaster::castFrameStub($function, [], $function, true);
$a[$prefix.'executing'] = $function[$prefix.'src'];
}
$a[Caster::PREFIX_VIRTUAL.'closed'] = false;
@@ -149,11 +157,11 @@ class ReflectionCaster
$a[$prefix.'modifiers'] = implode(' ', $n);
}
self::addMap($a, $c, array(
self::addMap($a, $c, [
'extends' => 'getParentClass',
'implements' => 'getInterfaceNames',
'constants' => 'getConstants',
));
]);
foreach ($c->getProperties() as $n) {
$a[$prefix.'properties'][$n->name] = $n;
@@ -174,17 +182,17 @@ class ReflectionCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
self::addMap($a, $c, array(
self::addMap($a, $c, [
'returnsReference' => 'returnsReference',
'returnType' => 'getReturnType',
'class' => 'getClosureScopeClass',
'this' => 'getClosureThis',
));
]);
if (isset($a[$prefix.'returnType'])) {
$v = $a[$prefix.'returnType'];
$v = $v->getName();
$a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, array(class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', ''));
$v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
$a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']);
}
if (isset($a[$prefix.'class'])) {
$a[$prefix.'class'] = new ClassStub($a[$prefix.'class']);
@@ -207,7 +215,7 @@ class ReflectionCaster
$a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']);
}
if ($v = $c->getStaticVariables()) {
if (!($filter & Caster::EXCLUDE_VERBOSE) && $v = $c->getStaticVariables()) {
foreach ($v as $k => &$v) {
if (\is_object($v)) {
$a[$prefix.'use']['$'.$k] = new CutStub($v);
@@ -237,33 +245,35 @@ class ReflectionCaster
{
$prefix = Caster::PREFIX_VIRTUAL;
self::addMap($a, $c, array(
self::addMap($a, $c, [
'position' => 'getPosition',
'isVariadic' => 'isVariadic',
'byReference' => 'isPassedByReference',
'allowsNull' => 'allowsNull',
));
]);
if ($v = $c->getType()) {
$a[$prefix.'typeHint'] = $v->getName();
$a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v;
}
if (isset($a[$prefix.'typeHint'])) {
$v = $a[$prefix.'typeHint'];
$a[$prefix.'typeHint'] = new ClassStub($v, array(class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', ''));
$a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']);
} else {
unset($a[$prefix.'allowsNull']);
}
try {
$a[$prefix.'default'] = $v = $c->getDefaultValue();
if ($c->isDefaultValueConstant()) {
$a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
if ($c->isOptional()) {
try {
$a[$prefix.'default'] = $v = $c->getDefaultValue();
if ($c->isDefaultValueConstant()) {
$a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
}
if (null === $v) {
unset($a[$prefix.'allowsNull']);
}
} catch (\ReflectionException $e) {
}
if (null === $v) {
unset($a[$prefix.'allowsNull']);
}
} catch (\ReflectionException $e) {
}
return $a;
@@ -277,9 +287,16 @@ class ReflectionCaster
return $a;
}
public static function castReference(\ReflectionReference $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId();
return $a;
}
public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
self::addMap($a, $c, [
'version' => 'getVersion',
'dependencies' => 'getDependencies',
'iniEntries' => 'getIniEntries',
@@ -288,19 +305,19 @@ class ReflectionCaster
'constants' => 'getConstants',
'functions' => 'getFunctions',
'classes' => 'getClasses',
));
]);
return $a;
}
public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
self::addMap($a, $c, [
'version' => 'getVersion',
'author' => 'getAuthor',
'copyright' => 'getCopyright',
'url' => 'getURL',
));
]);
return $a;
}
@@ -314,10 +331,14 @@ class ReflectionCaster
foreach ($a[$prefix.'parameters']->value as $k => $param) {
$signature .= ', ';
if ($type = $param->getType()) {
if (!$param->isOptional() && $param->allowsNull()) {
$signature .= '?';
if (!$type instanceof \ReflectionNamedType) {
$signature .= $type.' ';
} else {
if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) {
$signature .= '?';
}
$signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' ';
}
$signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' ';
}
$signature .= $k;
@@ -334,9 +355,11 @@ class ReflectionCaster
} elseif (\is_array($v)) {
$signature .= $v ? '[…'.\count($v).']' : '[]';
} elseif (\is_string($v)) {
$signature .= 10 > \strlen($v) && false === strpos($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'";
$signature .= 10 > \strlen($v) && !str_contains($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'";
} elseif (\is_bool($v)) {
$signature .= $v ? 'true' : 'false';
} elseif (\is_object($v)) {
$signature .= 'new '.substr(strrchr('\\'.get_debug_type($v), '\\'), 1);
} else {
$signature .= $v;
}
@@ -351,25 +374,29 @@ class ReflectionCaster
return $signature;
}
private static function addExtra(&$a, \Reflector $c)
private static function addExtra(array &$a, \Reflector $c)
{
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : array();
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : [];
if (method_exists($c, 'getFileName') && $m = $c->getFileName()) {
$x['file'] = new LinkStub($m, $c->getStartLine());
$x['line'] = $c->getStartLine().' to '.$c->getEndLine();
}
self::addMap($x, $c, self::$extraMap, '');
self::addMap($x, $c, self::EXTRA_MAP, '');
if ($x) {
$a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x);
}
}
private static function addMap(&$a, \Reflector $c, $map, $prefix = Caster::PREFIX_VIRTUAL)
private static function addMap(array &$a, $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL)
{
foreach ($map as $k => $m) {
if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) {
continue;
}
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
}

View File

@@ -17,9 +17,16 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts common resource types to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class ResourceCaster
{
/**
* @param \CurlHandle|resource $h
*
* @return array
*/
public static function castCurl($h, array $a, Stub $stub, $isNested)
{
return curl_getinfo($h);
@@ -41,7 +48,7 @@ class ResourceCaster
public static function castStream($stream, array $a, Stub $stub, $isNested)
{
$a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested);
if (isset($a['uri'])) {
if ($a['uri'] ?? false) {
$a['uri'] = new LinkStub($a['uri']);
}
@@ -69,4 +76,30 @@ class ResourceCaster
return $a;
}
public static function castOpensslX509($h, array $a, Stub $stub, $isNested)
{
$stub->cut = -1;
$info = openssl_x509_parse($h, false);
$pin = openssl_pkey_get_public($h);
$pin = openssl_pkey_get_details($pin)['key'];
$pin = \array_slice(explode("\n", $pin), 1, -2);
$pin = base64_decode(implode('', $pin));
$pin = base64_encode(hash('sha256', $pin, true));
$a += [
'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])),
'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])),
'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']),
'fingerprint' => new EnumStub([
'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)),
'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)),
'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)),
'pin-sha256' => new ConstStub($pin),
]),
];
return $a;
}
}

View File

@@ -17,15 +17,17 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts SPL related classes to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class SplCaster
{
private static $splFileObjectFlags = array(
private const SPL_FILE_OBJECT_FLAGS = [
\SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE',
\SplFileObject::READ_AHEAD => 'READ_AHEAD',
\SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY',
\SplFileObject::READ_CSV => 'READ_CSV',
);
];
public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested)
{
@@ -39,9 +41,9 @@ class SplCaster
public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
{
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c),
);
];
return $a;
}
@@ -52,10 +54,10 @@ class SplCaster
$mode = $c->getIteratorMode();
$c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
$a += array(
$a += [
$prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode),
$prefix.'dllist' => iterator_to_array($c),
);
];
$c->setIteratorMode($mode);
return $a;
@@ -63,7 +65,7 @@ class SplCaster
public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested)
{
static $map = array(
static $map = [
'path' => 'getPath',
'filename' => 'getFilename',
'basename' => 'getBasename',
@@ -86,9 +88,39 @@ class SplCaster
'dir' => 'isDir',
'link' => 'isLink',
'linkTarget' => 'getLinkTarget',
);
];
$prefix = Caster::PREFIX_VIRTUAL;
unset($a["\0SplFileInfo\0fileName"]);
unset($a["\0SplFileInfo\0pathName"]);
if (\PHP_VERSION_ID < 80000) {
if (false === $c->getPathname()) {
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
}
} else {
try {
$c->isReadable();
} catch (\RuntimeException $e) {
if ('Object not initialized' !== $e->getMessage()) {
throw $e;
}
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
} catch (\Error $e) {
if ('Object not initialized' !== $e->getMessage()) {
throw $e;
}
$a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state';
return $a;
}
}
foreach ($map as $key => $accessor) {
try {
@@ -97,7 +129,7 @@ class SplCaster
}
}
if (isset($a[$prefix.'realPath'])) {
if ($a[$prefix.'realPath'] ?? false) {
$a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']);
}
@@ -105,7 +137,7 @@ class SplCaster
$a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
}
static $mapDate = array('aTime', 'mTime', 'cTime');
static $mapDate = ['aTime', 'mTime', 'cTime'];
foreach ($mapDate as $key) {
if (isset($a[$prefix.$key])) {
$a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]);
@@ -117,14 +149,14 @@ class SplCaster
public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested)
{
static $map = array(
static $map = [
'csvControl' => 'getCsvControl',
'flags' => 'getFlags',
'maxLineLen' => 'getMaxLineLen',
'fstat' => 'fstat',
'eof' => 'eof',
'key' => 'key',
);
];
$prefix = Caster::PREFIX_VIRTUAL;
@@ -136,8 +168,8 @@ class SplCaster
}
if (isset($a[$prefix.'flags'])) {
$flagsArray = array();
foreach (self::$splFileObjectFlags as $value => $name) {
$flagsArray = [];
foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) {
if ($a[$prefix.'flags'] & $value) {
$flagsArray[] = $name;
}
@@ -146,37 +178,29 @@ class SplCaster
}
if (isset($a[$prefix.'fstat'])) {
$a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], array('dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks'));
$a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']);
}
return $a;
}
public static function castFixedArray(\SplFixedArray $c, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'storage' => $c->toArray(),
);
return $a;
}
public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested)
{
$storage = array();
$storage = [];
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
unset($a["\0SplObjectStorage\0storage"]);
$clone = clone $c;
foreach ($clone as $obj) {
$storage[] = array(
$storage[] = [
'object' => $obj,
'info' => $clone->getInfo(),
);
];
}
$a += array(
$a += [
Caster::PREFIX_VIRTUAL.'storage' => $storage,
);
];
return $a;
}
@@ -188,25 +212,33 @@ class SplCaster
return $a;
}
private static function castSplArray($c, array $a, Stub $stub, $isNested)
public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'object'] = $c->get();
return $a;
}
private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array
{
$prefix = Caster::PREFIX_VIRTUAL;
$class = $stub->class;
$flags = $c->getFlags();
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
$c->setFlags(\ArrayObject::STD_PROP_LIST);
$a = Caster::castObject($c, $class);
$a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class);
$c->setFlags($flags);
}
$a += array(
if (\PHP_VERSION_ID < 70400) {
$a[$prefix.'storage'] = $c->getArrayCopy();
}
$a += [
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
);
];
if ($c instanceof \ArrayObject) {
$a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass());
}
$a[$prefix.'storage'] = $c->getArrayCopy();
return $a;
}

View File

@@ -17,6 +17,8 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts a caster's Stub.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class StubCaster
{
@@ -35,7 +37,7 @@ class StubCaster
$stub->class = Stub::STRING_BINARY;
}
$a = array();
$a = [];
}
return $a;
@@ -51,7 +53,7 @@ class StubCaster
if ($isNested) {
$stub->cut += \count($a);
return array();
return [];
}
return $a;
@@ -66,7 +68,7 @@ class StubCaster
$stub->cut = $c->cut;
$stub->attr = $c->attr;
$a = array();
$a = [];
if ($c->value) {
foreach (array_keys($c->value) as $k) {

View File

@@ -14,23 +14,27 @@ namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @final since Symfony 4.4
*/
class SymfonyCaster
{
private static $requestGetters = array(
private const REQUEST_GETTERS = [
'pathInfo' => 'getPathInfo',
'requestUri' => 'getRequestUri',
'baseUrl' => 'getBaseUrl',
'basePath' => 'getBasePath',
'method' => 'getMethod',
'format' => 'getRequestFormat',
);
];
public static function castRequest(Request $request, array $a, Stub $stub, $isNested)
{
$clone = null;
foreach (self::$requestGetters as $prop => $getter) {
if (null === $a[Caster::PREFIX_PROTECTED.$prop]) {
foreach (self::REQUEST_GETTERS as $prop => $getter) {
$key = Caster::PREFIX_PROTECTED.$prop;
if (\array_key_exists($key, $a) && null === $a[$key]) {
if (null === $clone) {
$clone = clone $request;
}
@@ -40,4 +44,26 @@ class SymfonyCaster
return $a;
}
public static function castHttpClient($client, array $a, Stub $stub, $isNested)
{
$multiKey = sprintf("\0%s\0multi", \get_class($client));
if (isset($a[$multiKey])) {
$a[$multiKey] = new CutStub($a[$multiKey]);
}
return $a;
}
public static function castHttpClientResponse($response, array $a, Stub $stub, $isNested)
{
$stub->cut += \count($a);
$a = [];
foreach ($response->getInfo() as $k => $v) {
$a[Caster::PREFIX_VIRTUAL.$k] = $v;
}
return $a;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Caster;
use Ramsey\Uuid\UuidInterface;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
final class UuidCaster
{
public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested): array
{
$a += [
Caster::PREFIX_VIRTUAL.'uuid' => (string) $c,
];
return $a;
}
}

View File

@@ -1,4 +1,5 @@
<?php
/*
* This file is part of the Symfony package.
*
@@ -16,10 +17,12 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts XmlReader class to array representation.
*
* @author Baptiste Clavié <clavie.b@gmail.com>
*
* @final since Symfony 4.4
*/
class XmlReaderCaster
{
private static $nodeTypes = array(
private const NODE_TYPES = [
\XMLReader::NONE => 'NONE',
\XMLReader::ELEMENT => 'ELEMENT',
\XMLReader::ATTRIBUTE => 'ATTRIBUTE',
@@ -38,15 +41,31 @@ class XmlReaderCaster
\XMLReader::END_ELEMENT => 'END_ELEMENT',
\XMLReader::END_ENTITY => 'END_ENTITY',
\XMLReader::XML_DECLARATION => 'XML_DECLARATION',
);
];
public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, $isNested)
{
try {
$properties = [
'LOADDTD' => @$reader->getParserProperty(\XMLReader::LOADDTD),
'DEFAULTATTRS' => @$reader->getParserProperty(\XMLReader::DEFAULTATTRS),
'VALIDATE' => @$reader->getParserProperty(\XMLReader::VALIDATE),
'SUBST_ENTITIES' => @$reader->getParserProperty(\XMLReader::SUBST_ENTITIES),
];
} catch (\Error $e) {
$properties = [
'LOADDTD' => false,
'DEFAULTATTRS' => false,
'VALIDATE' => false,
'SUBST_ENTITIES' => false,
];
}
$props = Caster::PREFIX_VIRTUAL.'parserProperties';
$info = array(
$info = [
'localName' => $reader->localName,
'prefix' => $reader->prefix,
'nodeType' => new ConstStub(self::$nodeTypes[$reader->nodeType], $reader->nodeType),
'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType),
'depth' => $reader->depth,
'isDefault' => $reader->isDefault,
'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement,
@@ -55,20 +74,15 @@ class XmlReaderCaster
'value' => $reader->value,
'namespaceURI' => $reader->namespaceURI,
'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI,
$props => array(
'LOADDTD' => $reader->getParserProperty(\XMLReader::LOADDTD),
'DEFAULTATTRS' => $reader->getParserProperty(\XMLReader::DEFAULTATTRS),
'VALIDATE' => $reader->getParserProperty(\XMLReader::VALIDATE),
'SUBST_ENTITIES' => $reader->getParserProperty(\XMLReader::SUBST_ENTITIES),
),
);
$props => $properties,
];
if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, array(), $count)) {
if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) {
$info[$props] = new EnumStub($info[$props]);
$info[$props]->cut = $count;
}
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, array(), $count);
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count);
// +2 because hasValue and hasAttributes are always filtered
$stub->cut += $count + 2;

View File

@@ -17,33 +17,35 @@ use Symfony\Component\VarDumper\Cloner\Stub;
* Casts XML resources to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*
* @final since Symfony 4.4
*/
class XmlResourceCaster
{
private static $xmlErrors = array(
XML_ERROR_NONE => 'XML_ERROR_NONE',
XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY',
XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX',
XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS',
XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN',
XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN',
XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR',
XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH',
XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE',
XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT',
XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF',
XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY',
XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF',
XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY',
XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF',
XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF',
XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF',
XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI',
XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING',
XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING',
XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION',
XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING',
);
private const XML_ERRORS = [
\XML_ERROR_NONE => 'XML_ERROR_NONE',
\XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY',
\XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX',
\XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS',
\XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN',
\XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN',
\XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR',
\XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH',
\XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE',
\XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT',
\XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF',
\XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY',
\XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF',
\XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY',
\XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF',
\XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF',
\XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF',
\XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI',
\XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING',
\XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING',
\XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION',
\XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING',
];
public static function castXml($h, array $a, Stub $stub, $isNested)
{
@@ -52,8 +54,8 @@ class XmlResourceCaster
$a['current_line_number'] = xml_get_current_line_number($h);
$a['error_code'] = xml_get_error_code($h);
if (isset(self::$xmlErrors[$a['error_code']])) {
$a['error_code'] = new ConstStub(self::$xmlErrors[$a['error_code']], $a['error_code']);
if (isset(self::XML_ERRORS[$a['error_code']])) {
$a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']);
}
return $a;

View File

@@ -21,133 +21,165 @@ use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
*/
abstract class AbstractCloner implements ClonerInterface
{
public static $defaultCasters = array(
'__PHP_Incomplete_Class' => array('Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'),
public static $defaultCasters = [
'__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'],
'Symfony\Component\VarDumper\Caster\CutStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'),
'Symfony\Component\VarDumper\Caster\CutArrayStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'),
'Symfony\Component\VarDumper\Caster\ConstStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'),
'Symfony\Component\VarDumper\Caster\EnumStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'),
'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'],
'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'],
'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'],
'Closure' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'),
'Generator' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'),
'ReflectionType' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'),
'ReflectionGenerator' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'),
'ReflectionClass' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'),
'ReflectionFunctionAbstract' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'),
'ReflectionMethod' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'),
'ReflectionParameter' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'),
'ReflectionProperty' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'),
'ReflectionExtension' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'),
'ReflectionZendExtension' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'),
'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'],
'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'],
'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'],
'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'],
'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'],
'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'],
'Doctrine\Common\Persistence\ObjectManager' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'),
'Doctrine\Common\Proxy\Proxy' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'),
'Doctrine\ORM\Proxy\Proxy' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'),
'Doctrine\ORM\PersistentCollection' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'),
'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'],
'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'],
'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'],
'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'DOMException' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'),
'DOMStringList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'),
'DOMNameList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'),
'DOMImplementation' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'),
'DOMImplementationList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'),
'DOMNode' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'),
'DOMNameSpaceNode' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'),
'DOMDocument' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'),
'DOMNodeList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'),
'DOMNamedNodeMap' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'),
'DOMCharacterData' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'),
'DOMAttr' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'),
'DOMElement' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'),
'DOMText' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'),
'DOMTypeinfo' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'),
'DOMDomError' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'),
'DOMLocator' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'),
'DOMDocumentType' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'),
'DOMNotation' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'),
'DOMEntity' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'),
'DOMProcessingInstruction' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'),
'DOMXPath' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'),
'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'],
'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'],
'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'],
'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'],
'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'],
'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'],
'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'],
'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'],
'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'],
'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'],
'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'],
'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'],
'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'],
'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'],
'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'],
'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'],
'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'],
'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'],
'XmlReader' => array('Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'),
'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'],
'ErrorException' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'),
'Exception' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'),
'Error' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'),
'Symfony\Component\DependencyInjection\ContainerInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'),
'Symfony\Component\HttpFoundation\Request' => array('Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'),
'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'),
'Symfony\Component\VarDumper\Caster\TraceStub' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'),
'Symfony\Component\VarDumper\Caster\FrameStub' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'),
'Symfony\Component\Debug\Exception\SilencedErrorContext' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'),
'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'],
'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'],
'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'],
'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'],
'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\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\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'],
'ProxyManager\Proxy\ProxyInterface' => array('Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'),
'PHPUnit_Framework_MockObject_MockObject' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'),
'Prophecy\Prophecy\ProphecySubjectInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'),
'Mockery\MockInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'),
'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'],
'PDO' => array('Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'),
'PDOStatement' => array('Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'),
'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'],
'AMQPConnection' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'),
'AMQPChannel' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'),
'AMQPQueue' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'),
'AMQPExchange' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'),
'AMQPEnvelope' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'),
'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'],
'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'],
'ArrayObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'),
'ArrayIterator' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'),
'SplDoublyLinkedList' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'),
'SplFileInfo' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'),
'SplFileObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'),
'SplFixedArray' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFixedArray'),
'SplHeap' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'),
'SplObjectStorage' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'),
'SplPriorityQueue' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'),
'OuterIterator' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'),
'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'],
'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'],
'Redis' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'),
'RedisArray' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'),
'RedisCluster' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'),
'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'],
'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'],
'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'],
'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'],
'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'],
'DateTimeInterface' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'),
'DateInterval' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'),
'DateTimeZone' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'),
'DatePeriod' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'),
'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'],
'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'],
'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'],
'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'],
'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'],
'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'],
'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'],
'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'],
'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'],
'GMP' => array('Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'),
'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'],
'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'],
'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'],
'MessageFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'),
'NumberFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'),
'IntlTimeZone' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'),
'IntlCalendar' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'),
'IntlDateFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'),
'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'],
'Memcached' => array('Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'),
'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'],
':curl' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'),
':dba' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'),
':dba persistent' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'),
':gd' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'),
':mysql link' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'),
':pgsql large object' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'),
':pgsql link' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'),
':pgsql link persistent' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'),
':pgsql result' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'),
':process' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'),
':stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'),
':persistent stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'),
':stream-context' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'),
':xml' => array('Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'),
);
'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'],
':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'],
':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'],
];
protected $maxItems = 2500;
protected $maxString = -1;
protected $minDepth = 1;
private $casters = array();
private $casters = [];
private $prevErrorHandler;
private $classInfo = array();
private $classInfo = [];
private $filter = 0;
/**
@@ -176,7 +208,7 @@ 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;
}
}
@@ -221,14 +253,14 @@ abstract class AbstractCloner implements ClonerInterface
*/
public function cloneVar($var, $filter = 0)
{
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) {
if (E_RECOVERABLE_ERROR === $type || E_USER_ERROR === $type) {
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) {
if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) {
// Cloner never dies
throw new \ErrorException($msg, 0, $type, $file, $line);
}
if ($this->prevErrorHandler) {
return \call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context);
return ($this->prevErrorHandler)($type, $msg, $file, $line, $context);
}
return false;
@@ -261,7 +293,6 @@ abstract class AbstractCloner implements ClonerInterface
/**
* 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
@@ -271,30 +302,37 @@ abstract class AbstractCloner implements ClonerInterface
$obj = $stub->value;
$class = $stub->class;
if (isset($class[15]) && "\0" === $class[15] && 0 === strpos($class, "class@anonymous\x00")) {
$stub->class = get_parent_class($class).'@anonymous';
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 = array(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] = array($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];
}
$a = Caster::castObject($obj, $class, $hasDebugInfo);
$stub->attr += $fileInfo;
$a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class);
try {
while ($i--) {
@@ -305,7 +343,7 @@ abstract class AbstractCloner implements ClonerInterface
}
}
} catch (\Exception $e) {
$a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a;
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
}
return $a;
@@ -314,14 +352,13 @@ 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
*/
protected function castResource(Stub $stub, $isNested)
{
$a = array();
$a = [];
$res = $stub->value;
$type = $stub->class;
@@ -332,7 +369,7 @@ abstract class AbstractCloner implements ClonerInterface
}
}
} catch (\Exception $e) {
$a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a;
$a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a;
}
return $a;

View File

@@ -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;
@@ -38,6 +38,6 @@ class Cursor
public $hashLength = 0;
public $hashCut = 0;
public $stop = false;
public $attr = array();
public $attr = [];
public $skipChildren = false;
}

View File

@@ -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 The type of the value
* @return string|null The type of the value
*/
public function getType()
{
@@ -58,10 +60,12 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
if (Stub::TYPE_RESOURCE === $item->type) {
return $item->class.' resource';
}
return null;
}
/**
* @param bool $recursive Whether values should be resolved recursively or not
* @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
*/
@@ -79,7 +83,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
return $item->value;
}
$children = $item->position ? $this->data[$item->position] : array();
$children = $item->position ? $this->data[$item->position] : [];
foreach ($children as $k => $v) {
if ($recursive && !($v = $this->getStub($v)) instanceof Stub) {
@@ -104,15 +108,23 @@ 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, \gettype($value)));
}
yield from $value;
@@ -123,35 +135,59 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
if (null !== $data = $this->seek($key)) {
$item = $this->getStub($data->data[$data->position][$data->key]);
return $item instanceof Stub || array() === $item ? $data : $item;
return $item instanceof Stub || [] === $item ? $data : $item;
}
return null;
}
/**
* @return bool
*/
public function __isset($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();
@@ -168,7 +204,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
*
* @param int $maxDepth The max dumped depth level
*
* @return self A clone of $this
* @return static
*/
public function withMaxDepth($maxDepth)
{
@@ -183,7 +219,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
*
* @param int $maxItemsPerDepth The max number of items dumped per depth level
*
* @return self A clone of $this
* @return static
*/
public function withMaxItemsPerDepth($maxItemsPerDepth)
{
@@ -198,7 +234,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
*
* @param bool $useRefHandles False to hide global ref. handles
*
* @return self A clone of $this
* @return static
*/
public function withRefHandles($useRefHandles)
{
@@ -208,12 +244,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 self|null A clone of $this or null if the key is not set
* @return static|null Null if the key is not set
*/
public function seek($key)
{
@@ -223,9 +270,9 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
$item = $item->value;
}
if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) {
return;
return null;
}
$keys = array($key);
$keys = [$key];
switch ($item->type) {
case Stub::TYPE_OBJECT:
@@ -238,14 +285,14 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
case Stub::TYPE_RESOURCE:
break;
default:
return;
return null;
}
$data = null;
$children = $this->data[$item->position];
foreach ($keys as $key) {
if (isset($children[$key]) || array_key_exists($key, $children)) {
if (isset($children[$key]) || \array_key_exists($key, $children)) {
$data = clone $this;
$data->key = $key;
$data->position = $item->position;
@@ -261,19 +308,27 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
*/
public function dump(DumperInterface $dumper)
{
$refs = array(0);
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
$refs = [0];
$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;
@@ -281,21 +336,21 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
$firstSeen = true;
if (!$item instanceof Stub) {
$cursor->attr = array();
$cursor->attr = [];
$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)])) {
if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) {
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
} else {
$firstSeen = false;
}
$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);
@@ -322,10 +377,10 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
if ($cut >= 0) {
$cut += \count($children);
}
$children = array();
$children = [];
}
} else {
$children = array();
$children = [];
}
switch ($item->type) {
case Stub::TYPE_STRING:
@@ -356,7 +411,7 @@ class Data implements \ArrayAccess, \Countable, \IteratorAggregate
break;
default:
throw new \RuntimeException(sprintf('Unexpected Stub type: %s', $item->type));
throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type));
}
} elseif ('array' === $type) {
$dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
@@ -371,17 +426,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;

View File

@@ -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);
/**
* 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);
/**
* 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 $class The object class, resource type or array count
* @param bool $hasChild When the dump of the hash has child item
* @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);
/**
* 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 $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
* @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);
}

View File

@@ -16,19 +16,19 @@ namespace Symfony\Component\VarDumper\Cloner;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Stub implements \Serializable
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 = '';
@@ -37,21 +37,31 @@ class Stub implements \Serializable
public $handle = 0;
public $refCount = 0;
public $position = 0;
public $attr = array();
public $attr = [];
private static $defaultProperties = [];
/**
* @internal
*/
public function serialize()
public function __sleep(): array
{
return \serialize(array($this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr));
}
$properties = [];
/**
* @internal
*/
public function unserialize($serialized)
{
list($this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr) = \unserialize($serialized);
if (!isset(self::$defaultProperties[$c = static::class])) {
self::$defaultProperties[$c] = get_class_vars($c);
foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) {
unset(self::$defaultProperties[$c][$k]);
}
}
foreach (self::$defaultProperties[$c] as $k => $v) {
if ($this->$k !== $v) {
$properties[] = $k;
}
}
return $properties;
}
}

View File

@@ -17,7 +17,7 @@ namespace Symfony\Component\VarDumper\Cloner;
class VarCloner extends AbstractCloner
{
private static $gid;
private static $arrayCache = array();
private static $arrayCache = [];
/**
* {@inheritdoc}
@@ -27,25 +27,26 @@ 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 = array(array($var)); // This breadth-first queue is the return value
$indexedArrays = array(); // Map of queue indexes that hold numerically indexed arrays
$hardRefs = array(); // Map of original zval ids 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
$values = array(); // Map of stub objects' ids to original values
$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 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;
$currentDepth = 0; // Current tree depth
$currentDepthFinalIndex = 0; // Final $queue index for current tree depth
$minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached
$cookie = (object) array(); // Unique object used to detect hard references
$cookie = (object) []; // Unique object used to detect hard references
$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
if (!$gid = self::$gid) {
$gid = self::$gid = uniqid(mt_rand(), true); // Unique string used to detect the special $GLOBALS variable
$gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable
}
$arrayStub = new Stub();
$arrayStub->type = Stub::TYPE_ARRAY;
@@ -68,35 +69,52 @@ class VarCloner extends AbstractCloner
if (\is_int($k)) {
continue;
}
foreach (array($k => true) as $gk => $gv) {
foreach ([$k => true] as $gk => $gv) {
}
if ($gk !== $k) {
$fromObjCast = true;
$refs = $vals = \array_values($queue[$i]);
$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
$refs[$k] = $cookie;
if ($zvalIsRef = $vals[$k] === $cookie) {
if (\PHP_VERSION_ID >= 70400) {
$zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null;
} else {
$refs[$k] = $cookie;
$zvalRef = $vals[$k] === $cookie;
}
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_id($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_id($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
// If $v is a nested structure, put that structure in array $a
@@ -106,27 +124,26 @@ class VarCloner extends AbstractCloner
case \is_int($v):
case \is_float($v):
continue 2;
case \is_string($v):
if ('' === $v) {
continue 2;
}
if (!\preg_match('//u', $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) {
$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');
} else {
continue 2;
}
@@ -152,13 +169,24 @@ class VarCloner extends AbstractCloner
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])) {
if (\PHP_VERSION_ID < 80100 && ($a[$gid] = true) && isset($v[$gid])) {
unset($v[$gid]);
$a = array();
$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;
}
$a[$gk] = &$gv;
}
unset($gv);
@@ -172,7 +200,7 @@ class VarCloner extends AbstractCloner
case \is_object($v):
case $v instanceof \__PHP_Incomplete_Class:
if (empty($objRefs[$h = \spl_object_id($v)])) {
if (empty($objRefs[$h = spl_object_id($v)])) {
$stub = new Stub();
$stub->type = Stub::TYPE_OBJECT;
$stub->class = \get_class($v);
@@ -183,7 +211,7 @@ class VarCloner extends AbstractCloner
if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
break;
}
$stub->handle = $h = \spl_object_id($stub->value);
$stub->handle = $h = spl_object_id($stub->value);
}
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) {
@@ -193,6 +221,7 @@ class VarCloner extends AbstractCloner
}
if (empty($objRefs[$h])) {
$objRefs[$h] = $stub;
$objects[] = $v;
} else {
$stub = $objRefs[$h];
++$stub->refCount;
@@ -204,7 +233,7 @@ class VarCloner extends AbstractCloner
if (empty($resRefs[$h = (int) $v])) {
$stub = new Stub();
$stub->type = Stub::TYPE_RESOURCE;
if ('Unknown' === $stub->class = @\get_resource_type($v)) {
if ('Unknown' === $stub->class = @get_resource_type($v)) {
$stub->class = 'Closed';
}
$stub->value = $v;
@@ -232,7 +261,7 @@ class VarCloner extends AbstractCloner
$stub->position = $len++;
} elseif ($pos < $maxItems) {
if ($maxItems < $pos += \count($a)) {
$a = \array_slice($a, 0, $maxItems - $pos);
$a = \array_slice($a, 0, $maxItems - $pos, true);
if ($stub->cut >= 0) {
$stub->cut += $pos - $maxItems;
}
@@ -247,29 +276,31 @@ class VarCloner extends AbstractCloner
if ($arrayStub === $stub) {
if ($arrayStub->cut) {
$stub = array($arrayStub->cut, $arrayStub->class => $arrayStub->position);
$stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position];
$arrayStub->cut = 0;
} elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) {
$stub = self::$arrayCache[$arrayStub->class][$arrayStub->position];
} else {
self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = array($arrayStub->class => $arrayStub->position);
self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position];
}
}
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;
}
}
if ($fromObjCast) {
$fromObjCast = false;
$refs = $vals;
$vals = array();
$vals = [];
$j = -1;
foreach ($queue[$i] as $k => $v) {
foreach (array($k => true) as $gk => $gv) {
foreach ([$k => true] as $gk => $gv) {
}
if ($gk !== $k) {
$vals = (object) $vals;

View File

@@ -11,6 +11,7 @@
namespace Symfony\Component\VarDumper\Command\Descriptor;
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
@@ -28,18 +29,20 @@ class CliDescriptor implements DumpDescriptorInterface
{
private $dumper;
private $lastIdentifier;
private $supportsHref;
public function __construct(CliDumper $dumper)
{
$this->dumper = $dumper;
$this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref');
}
public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void
{
$io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput(array()), $output);
$io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output);
$this->dumper->setColors($output->isDecorated());
$rows = array(array('date', date('r', $context['timestamp'])));
$rows = [['date', date('r', (int) $context['timestamp'])]];
$lastIdentifier = $this->lastIdentifier;
$this->lastIdentifier = $clientId;
@@ -49,7 +52,7 @@ class CliDescriptor implements DumpDescriptorInterface
$this->lastIdentifier = $request['identifier'];
$section = sprintf('%s %s', $request['method'], $request['uri']);
if ($controller = $request['controller']) {
$rows[] = array('controller', rtrim($this->dumper->dump($controller, true), "\n"));
$rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")];
}
} elseif (isset($context['cli'])) {
$this->lastIdentifier = $context['cli']['identifier'];
@@ -62,16 +65,20 @@ class CliDescriptor implements DumpDescriptorInterface
if (isset($context['source'])) {
$source = $context['source'];
$rows[] = array('source', sprintf('%s on line %d', $source['name'], $source['line']));
$file = $source['file_relative'] ?? $source['file'];
$rows[] = array('file', $file);
$sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']);
$fileLink = $source['file_link'] ?? null;
if ($this->supportsHref && $fileLink) {
$sourceInfo = sprintf('<href=%s>%s</>', $fileLink, $sourceInfo);
}
$rows[] = ['source', $sourceInfo];
$file = $source['file_relative'] ?? $source['file'];
$rows[] = ['file', $file];
}
$io->table(array(), $rows);
$io->table([], $rows);
if (isset($fileLink)) {
$io->writeln(array('<info>Open source in your IDE/browser:</info>', $fileLink));
if (!$this->supportsHref && isset($fileLink)) {
$io->writeln(['<info>Open source in your IDE/browser:</info>', $fileLink]);
$io->newLine();
}

View File

@@ -44,7 +44,7 @@ class HtmlDescriptor implements DumpDescriptorInterface
$title = '-';
if (isset($context['request'])) {
$request = $context['request'];
$controller = "<span class='dumped-tag'>{$this->dumper->dump($request['controller'], true, array('maxDepth' => 0))}</span>";
$controller = "<span class='dumped-tag'>{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}</span>";
$title = sprintf('<code>%s</code> <a href="%s">%s</a>', $request['method'], $uri = $request['uri'], $uri);
$dedupIdentifier = $request['identifier'];
} elseif (isset($context['cli'])) {
@@ -57,7 +57,7 @@ class HtmlDescriptor implements DumpDescriptorInterface
$sourceDescription = '';
if (isset($context['source'])) {
$source = $context['source'];
$projectDir = $source['project_dir'];
$projectDir = $source['project_dir'] ?? null;
$sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']);
if (isset($source['file_link'])) {
$sourceDescription = sprintf('<a href="%s">%s</a>', $source['file_link'], $sourceDescription);
@@ -65,10 +65,10 @@ class HtmlDescriptor implements DumpDescriptorInterface
}
$isoDate = $this->extractDate($context, 'c');
$tags = array_filter(array(
$tags = array_filter([
'controller' => $controller ?? null,
'project dir' => $projectDir ?? null,
));
]);
$output->writeln(<<<HTML
<article data-dedup-id="$dedupIdentifier">
@@ -94,7 +94,7 @@ HTML
private function extractDate(array $context, string $format = 'r'): string
{
return date($format, $context['timestamp']);
return date($format, (int) $context['timestamp']);
}
private function renderTags(array $tags): string

View File

@@ -41,13 +41,13 @@ class ServerDumpCommand extends Command
/** @var DumpDescriptorInterface[] */
private $descriptors;
public function __construct(DumpServer $server, array $descriptors = array())
public function __construct(DumpServer $server, array $descriptors = [])
{
$this->server = $server;
$this->descriptors = $descriptors + array(
$this->descriptors = $descriptors + [
'cli' => new CliDescriptor(new CliDumper()),
'html' => new HtmlDescriptor(new HtmlDumper()),
);
];
parent::__construct();
}
@@ -58,7 +58,7 @@ class ServerDumpCommand extends Command
$this
->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', $availableFormats), 'cli')
->setDescription('Starts a dump server that collects and displays dumps in a single place')
->setDescription('Start a dump server that collects and displays dumps in a single place')
->setHelp(<<<'EOF'
<info>%command.name%</info> starts a dump server that collects and displays
dumps in a single place for debugging you application:
@@ -75,7 +75,7 @@ EOF
;
}
protected function execute(InputInterface $input, OutputInterface $output)
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$format = $input->getOption('format');
@@ -95,5 +95,7 @@ EOF
$this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) {
$descriptor->describe($io, $data, $context, $clientId);
});
return 0;
}
}

View File

@@ -21,10 +21,10 @@ use Symfony\Component\VarDumper\Cloner\DumperInterface;
*/
abstract class AbstractDumper implements DataDumperInterface, DumperInterface
{
const DUMP_LIGHT_ARRAY = 1;
const DUMP_STRING_LENGTH = 2;
const DUMP_COMMA_SEPARATOR = 4;
const DUMP_TRAILING_COMMA = 8;
public const DUMP_LIGHT_ARRAY = 1;
public const DUMP_STRING_LENGTH = 2;
public const DUMP_COMMA_SEPARATOR = 4;
public const DUMP_TRAILING_COMMA = 8;
public static $defaultOutput = 'php://output';
@@ -35,19 +35,18 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
protected $indentPad = ' ';
protected $flags;
private $charset;
private $charset = '';
/**
* @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput
* @param string $charset The default character encoding to use for non-UTF8 strings
* @param string|null $charset The default character encoding to use for non-UTF8 strings
* @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation
*/
public function __construct($output = null, string $charset = null, int $flags = 0)
{
$this->flags = $flags;
$this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8');
$this->decimalPoint = localeconv();
$this->decimalPoint = $this->decimalPoint['decimal_point'];
$this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8');
$this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point'];
$this->setOutput($output ?: static::$defaultOutput);
if (!$output && \is_string(static::$defaultOutput)) {
static::$defaultOutput = $this->outputStream;
@@ -63,17 +62,17 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
*/
public function setOutput($output)
{
$prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
$prev = $this->outputStream ?? $this->lineDumper;
if (\is_callable($output)) {
$this->outputStream = null;
$this->lineDumper = $output;
} else {
if (\is_string($output)) {
$output = fopen($output, 'wb');
$output = fopen($output, 'w');
}
$this->outputStream = $output;
$this->lineDumper = array($this, 'echoLine');
$this->lineDumper = [$this, 'echoLine'];
}
return $prev;
@@ -116,22 +115,20 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
/**
* Dumps a Data object.
*
* @param Data $data A Data object
* @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump
*
* @return string|null The dump as string when $output is true
*/
public function dump(Data $data, $output = null)
{
$this->decimalPoint = localeconv();
$this->decimalPoint = $this->decimalPoint['decimal_point'];
$this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point'];
if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(LC_NUMERIC, 0) : null) {
setlocale(LC_NUMERIC, 'C');
if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(\LC_NUMERIC, 0) : null) {
setlocale(\LC_NUMERIC, 'C');
}
if ($returnDump = true === $output) {
$output = fopen('php://memory', 'r+b');
$output = fopen('php://memory', 'r+');
}
if ($output) {
$prevOutput = $this->setOutput($output);
@@ -151,9 +148,11 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
$this->setOutput($prevOutput);
}
if ($locale) {
setlocale(LC_NUMERIC, $locale);
setlocale(\LC_NUMERIC, $locale);
}
}
return null;
}
/**
@@ -164,7 +163,7 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
*/
protected function dumpLine($depth)
{
\call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
($this->lineDumper)($this->line, $depth, $this->indentPad);
$this->line = '';
}
@@ -185,13 +184,13 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface
/**
* Converts a non-UTF-8 string to UTF-8.
*
* @param string $s The non-UTF-8 string to convert
* @param string|null $s The non-UTF-8 string to convert
*
* @return string The string converted to UTF-8
* @return string|null The string converted to UTF-8
*/
protected function utf8Encode($s)
{
if (preg_match('//u', $s)) {
if (null === $s || preg_match('//u', $s)) {
return $s;
}

View File

@@ -26,9 +26,9 @@ class CliDumper extends AbstractDumper
protected $colors;
protected $maxStringWidth = 0;
protected $styles = array(
protected $styles = [
// See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
'default' => '38;5;208',
'default' => '0;38;5;208',
'num' => '1;38;5;38',
'const' => '1;38;5;208',
'str' => '1;38;5;113',
@@ -40,21 +40,27 @@ class CliDumper extends AbstractDumper
'meta' => '38;5;170',
'key' => '38;5;113',
'index' => '38;5;38',
);
];
protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/';
protected static $controlCharsMap = array(
protected static $controlCharsMap = [
"\t" => '\t',
"\n" => '\n',
"\v" => '\v',
"\f" => '\f',
"\r" => '\r',
"\033" => '\e',
);
];
protected $collapseNextHash = false;
protected $expandNextHash = false;
private $displayOptions = [
'fileLinkFormat' => null,
];
private $handlesHrefGracefully;
/**
* {@inheritdoc}
*/
@@ -64,7 +70,7 @@ class CliDumper extends AbstractDumper
if ('\\' === \DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) {
// Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI
$this->setStyles(array(
$this->setStyles([
'default' => '31',
'num' => '1;34',
'const' => '1;31',
@@ -74,8 +80,10 @@ class CliDumper extends AbstractDumper
'meta' => '35',
'key' => '32',
'index' => '34',
));
]);
}
$this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l';
}
/**
@@ -108,6 +116,16 @@ class CliDumper extends AbstractDumper
$this->styles = $styles + $this->styles;
}
/**
* Configures display options.
*
* @param array $displayOptions A map of display options to customize the behavior
*/
public function setDisplayOptions(array $displayOptions)
{
$this->displayOptions = $displayOptions + $this->displayOptions;
}
/**
* {@inheritdoc}
*/
@@ -131,12 +149,12 @@ class CliDumper extends AbstractDumper
$style = 'num';
switch (true) {
case INF === $value: $value = 'INF'; break;
case -INF === $value: $value = '-INF'; break;
case \INF === $value: $value = 'INF'; break;
case -\INF === $value: $value = '-INF'; break;
case is_nan($value): $value = 'NAN'; break;
default:
$value = (string) $value;
if (false === strpos($value, $this->decimalPoint)) {
if (!str_contains($value, $this->decimalPoint)) {
$value .= $this->decimalPoint.'0';
}
break;
@@ -152,7 +170,7 @@ class CliDumper extends AbstractDumper
break;
default:
$attr += array('value' => $this->utf8Encode($value));
$attr += ['value' => $this->utf8Encode($value)];
$value = $this->utf8Encode($type);
break;
}
@@ -177,10 +195,10 @@ class CliDumper extends AbstractDumper
$this->line .= '""';
$this->endValue($cursor);
} else {
$attr += array(
$attr += [
'length' => 0 <= $cut ? mb_strlen($str, 'UTF-8') + $cut : 0,
'binary' => $bin,
);
];
$str = explode("\n", $str);
if (isset($str[1]) && !isset($str[2]) && !isset($str[1][0])) {
unset($str[1]);
@@ -255,7 +273,12 @@ class CliDumper extends AbstractDumper
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
if (null === $this->colors) {
$this->colors = $this->supportsColors();
}
$this->dumpKey($cursor);
$attr = $cursor->attr;
if ($this->collapseNextHash) {
$cursor->skipChildren = true;
@@ -264,17 +287,17 @@ class CliDumper extends AbstractDumper
$class = $this->utf8Encode($class);
if (Cursor::HASH_OBJECT === $type) {
$prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{';
$prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).(empty($attr['cut_hash']) ? ' {' : '') : '{';
} elseif (Cursor::HASH_RESOURCE === $type) {
$prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' ');
$prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' ');
} else {
$prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '[';
}
if ($cursor->softRefCount || 0 < $cursor->softRefHandle) {
$prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), array('count' => $cursor->softRefCount));
if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) {
$prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]);
} elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) {
$prefix .= $this->style('ref', '&'.$cursor->hardRefTo, array('count' => $cursor->hardRefCount));
$prefix .= $this->style('ref', '&'.$cursor->hardRefTo, ['count' => $cursor->hardRefCount]);
} elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) {
$prefix = substr($prefix, 0, -1);
}
@@ -291,17 +314,19 @@ class CliDumper extends AbstractDumper
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut)
{
$this->dumpEllipsis($cursor, $hasChild, $cut);
$this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : ''));
if (empty($cursor->attr['cut_hash'])) {
$this->dumpEllipsis($cursor, $hasChild, $cut);
$this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : ''));
}
$this->endValue($cursor);
}
/**
* Dumps an ellipsis for cut children.
*
* @param Cursor $cursor The Cursor position in the dump
* @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
* @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
*/
protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut)
{
@@ -318,8 +343,6 @@ class CliDumper extends AbstractDumper
/**
* Dumps a key in a hash structure.
*
* @param Cursor $cursor The Cursor position in the dump
*/
protected function dumpKey(Cursor $cursor)
{
@@ -327,7 +350,7 @@ class CliDumper extends AbstractDumper
if ($cursor->hashKeyIsBinary) {
$key = $this->utf8Encode($key);
}
$attr = array('binary' => $cursor->hashKeyIsBinary);
$attr = ['binary' => $cursor->hashKeyIsBinary];
$bin = $cursor->hashKeyIsBinary ? 'b' : '';
$style = 'key';
switch ($cursor->hashType) {
@@ -364,7 +387,7 @@ class CliDumper extends AbstractDumper
$style = 'meta';
if (isset($key[0][1])) {
parse_str(substr($key[0], 1), $attr);
$attr += array('binary' => $cursor->hashKeyIsBinary);
$attr += ['binary' => $cursor->hashKeyIsBinary];
}
break;
case '*':
@@ -386,16 +409,16 @@ class CliDumper extends AbstractDumper
}
}
$this->line .= $bin.$this->style($style, $key[1], $attr).(isset($attr['separator']) ? $attr['separator'] : ': ');
$this->line .= $bin.$this->style($style, $key[1], $attr).($attr['separator'] ?? ': ');
} else {
// This case should not happen
$this->line .= '-'.$bin.'"'.$this->style('private', $key, array('class' => '')).'": ';
$this->line .= '-'.$bin.'"'.$this->style('private', $key, ['class' => '']).'": ';
}
break;
}
if ($cursor->hardRefTo) {
$this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), array('count' => $cursor->hardRefCount)).' ';
$this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), ['count' => $cursor->hardRefCount]).' ';
}
}
}
@@ -409,15 +432,20 @@ class CliDumper extends AbstractDumper
*
* @return string The value with style decoration
*/
protected function style($style, $value, $attr = array())
protected function style($style, $value, $attr = [])
{
if (null === $this->colors) {
$this->colors = $this->supportsColors();
}
if (null === $this->handlesHrefGracefully) {
$this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR')
&& (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100);
}
if (isset($attr['ellipsis'], $attr['ellipsis-type'])) {
$prefix = substr($value, 0, -$attr['ellipsis']);
if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && 0 === strpos($prefix, $_SERVER[$pwd])) {
if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && str_starts_with($prefix, $_SERVER[$pwd])) {
$prefix = '.'.substr($prefix, \strlen($_SERVER[$pwd]));
}
if (!empty($attr['ellipsis-tail'])) {
@@ -427,19 +455,19 @@ class CliDumper extends AbstractDumper
$value = substr($value, -$attr['ellipsis']);
}
return $this->style('default', $prefix).$this->style($style, $value);
}
$value = $this->style('default', $prefix).$this->style($style, $value);
$style = $this->styles[$style];
goto href;
}
$map = static::$controlCharsMap;
$startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : '';
$endCchr = $this->colors ? "\033[m\033[{$style}m" : '';
$endCchr = $this->colors ? "\033[m\033[{$this->styles[$style]}m" : '';
$value = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $startCchr, $endCchr) {
$s = $startCchr;
$c = $c[$i = 0];
do {
$s .= isset($map[$c[$i]]) ? $map[$c[$i]] : sprintf('\x%02X', \ord($c[$i]));
$s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i]));
} while (isset($c[++$i]));
return $s.$endCchr;
@@ -449,15 +477,31 @@ class CliDumper extends AbstractDumper
if ($cchrCount && "\033" === $value[0]) {
$value = substr($value, \strlen($startCchr));
} else {
$value = "\033[{$style}m".$value;
$value = "\033[{$this->styles[$style]}m".$value;
}
if ($cchrCount && $endCchr === substr($value, -\strlen($endCchr))) {
if ($cchrCount && str_ends_with($value, $endCchr)) {
$value = substr($value, 0, -\strlen($endCchr));
} else {
$value .= "\033[{$this->styles['default']}m";
}
}
href:
if ($this->colors && $this->handlesHrefGracefully) {
if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) {
if ('note' === $style) {
$value .= "\033]8;;{$href}\033\\^\033]8;;\033\\";
} else {
$attr['href'] = $href;
}
}
if (isset($attr['href'])) {
$value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\";
}
} elseif ($attr['if_links'] ?? false) {
return '';
}
return $value;
}
@@ -495,8 +539,8 @@ class CliDumper extends AbstractDumper
}
}
$h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null);
$h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream;
$h = stream_get_meta_data($this->outputStream) + ['wrapper_type' => null];
$h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'w') : $this->outputStream;
return static::$defaultColors = $this->hasColorSupport($h);
}
@@ -514,6 +558,10 @@ class CliDumper extends AbstractDumper
protected function endValue(Cursor $cursor)
{
if (-1 === $cursor->hashType) {
return;
}
if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) {
if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) {
$this->line .= ',';
@@ -532,15 +580,18 @@ class CliDumper extends AbstractDumper
* https://github.com/composer/xdebug-handler
*
* @param mixed $stream A CLI output stream
*
* @return bool
*/
private function hasColorSupport($stream)
private function hasColorSupport($stream): bool
{
if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) {
return false;
}
// Follow https://no-color.org/
if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) {
return false;
}
if ('Hyper' === getenv('TERM_PROGRAM')) {
return true;
}
@@ -572,10 +623,8 @@ class CliDumper extends AbstractDumper
* Note that this does not check an output stream, but relies on environment
* variables from known implementations, or a PHP and Windows version that
* supports true color.
*
* @return bool
*/
private function isWindowsTrueColor()
private function isWindowsTrueColor(): bool
{
$result = 183 <= getenv('ANSICON_VER')
|| 'ON' === getenv('ConEmuANSI')
@@ -594,4 +643,13 @@ class CliDumper extends AbstractDumper
return $result;
}
private function getSourceLink(string $file, int $line)
{
if ($fmt = $this->displayOptions['fileLinkFormat']) {
return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line);
}
return false;
}
}

View File

@@ -24,9 +24,9 @@ final class CliContextProvider implements ContextProviderInterface
return null;
}
return array(
'command_line' => $commandLine = implode(' ', $_SERVER['argv']),
return [
'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []),
'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']),
);
];
}
}

View File

@@ -12,6 +12,7 @@
namespace Symfony\Component\VarDumper\Dumper\ContextProvider;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
use Symfony\Component\VarDumper\Cloner\VarCloner;
/**
@@ -29,6 +30,7 @@ final class RequestContextProvider implements ContextProviderInterface
$this->requestStack = $requestStack;
$this->cloner = new VarCloner();
$this->cloner->setMaxItems(0);
$this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO);
}
public function getContext(): ?array
@@ -39,11 +41,11 @@ final class RequestContextProvider implements ContextProviderInterface
$controller = $request->attributes->get('_controller');
return array(
return [
'uri' => $request->getUri(),
'method' => $request->getMethod(),
'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller,
'identifier' => spl_object_hash($request),
);
];
}
}

View File

@@ -40,7 +40,7 @@ final class SourceContextProvider implements ContextProviderInterface
public function getContext(): ?array
{
$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit);
$trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit);
$file = $trace[1]['file'];
$line = $trace[1]['line'];
@@ -52,11 +52,11 @@ final class SourceContextProvider implements ContextProviderInterface
&& 'dump' === $trace[$i]['function']
&& VarDumper::class === $trace[$i]['class']
) {
$file = $trace[$i]['file'];
$line = $trace[$i]['line'];
$file = $trace[$i]['file'] ?? $file;
$line = $trace[$i]['line'] ?? $line;
while (++$i < $this->limit) {
if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) {
if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && !str_starts_with($trace[$i]['function'], 'call_user_func')) {
$file = $trace[$i]['file'];
$line = $trace[$i]['line'];
@@ -72,7 +72,7 @@ final class SourceContextProvider implements ContextProviderInterface
if ($src) {
$src = explode("\n", $src);
$fileExcerpt = array();
$fileExcerpt = [];
for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) {
$fileExcerpt[] = '<li'.($i === $line ? ' class="selected"' : '').'><code>'.$this->htmlEncode($src[$i - 1]).'</code></li>';
@@ -93,12 +93,12 @@ final class SourceContextProvider implements ContextProviderInterface
$name = substr($name, strrpos($name, '/') + 1);
}
$context = array('name' => $name, 'file' => $file, 'line' => $line);
$context = ['name' => $name, 'file' => $file, 'line' => $line];
$context['file_excerpt'] = $fileExcerpt;
if (null !== $this->projectDir) {
$context['project_dir'] = $this->projectDir;
if (0 === strpos($file, $this->projectDir)) {
if (str_starts_with($file, $this->projectDir)) {
$context['file_relative'] = ltrim(substr($file, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR);
}
}

View File

@@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Dumper;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
/**
* @author Kévin Thérage <therage.kevin@gmail.com>
*/
class ContextualizedDumper implements DataDumperInterface
{
private $wrappedDumper;
private $contextProviders;
/**
* @param ContextProviderInterface[] $contextProviders
*/
public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders)
{
$this->wrappedDumper = $wrappedDumper;
$this->contextProviders = $contextProviders;
}
public function dump(Data $data)
{
$context = [];
foreach ($this->contextProviders as $contextProvider) {
$context[\get_class($contextProvider)] = $contextProvider->getContext();
}
$this->wrappedDumper->dump($data->withContext($context));
}
}

View File

@@ -23,8 +23,8 @@ class HtmlDumper extends CliDumper
{
public static $defaultOutput = 'php://output';
protected static $themes = array(
'dark' => array(
protected static $themes = [
'dark' => [
'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all',
'num' => 'font-weight:bold; color:#1299DA',
'const' => 'font-weight:bold',
@@ -39,8 +39,8 @@ class HtmlDumper extends CliDumper
'index' => 'color:#1299DA',
'ellipsis' => 'color:#FF8400',
'ns' => 'user-select:none;',
),
'light' => array(
],
'light' => [
'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all',
'num' => 'font-weight:bold; color:#1299DA',
'const' => 'font-weight:bold',
@@ -55,8 +55,8 @@ class HtmlDumper extends CliDumper
'index' => 'color:#1299DA',
'ellipsis' => 'color:#CC7832',
'ns' => 'user-select:none;',
),
);
],
];
protected $dumpHeader;
protected $dumpPrefix = '<pre class=sf-dump id=%s data-indent-pad="%s">';
@@ -67,12 +67,12 @@ class HtmlDumper extends CliDumper
protected $lastDepth = -1;
protected $styles;
private $displayOptions = array(
private $displayOptions = [
'maxDepth' => 1,
'maxStringLength' => 160,
'fileLinkFormat' => null,
);
private $extraDisplayOptions = array();
];
private $extraDisplayOptions = [];
/**
* {@inheritdoc}
@@ -81,7 +81,7 @@ class HtmlDumper extends CliDumper
{
AbstractDumper::__construct($output, $charset, $flags);
$this->dumpId = 'sf-dump-'.mt_rand();
$this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
$this->styles = static::$themes['dark'] ?? self::$themes['dark'];
}
@@ -139,7 +139,7 @@ class HtmlDumper extends CliDumper
/**
* {@inheritdoc}
*/
public function dump(Data $data, $output = null, array $extraDisplayOptions = array())
public function dump(Data $data, $output = null, array $extraDisplayOptions = [])
{
$this->extraDisplayOptions = $extraDisplayOptions;
$result = parent::dump($data, $output);
@@ -153,13 +153,13 @@ class HtmlDumper extends CliDumper
*/
protected function getDumpHeader()
{
$this->headerIsDumped = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
$this->headerIsDumped = $this->outputStream ?? $this->lineDumper;
if (null !== $this->dumpHeader) {
return $this->dumpHeader;
}
$line = str_replace('{$options}', json_encode($this->displayOptions, JSON_FORCE_OBJECT), <<<'EOHTML'
$line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML'
<script>
Sfdump = window.Sfdump || (function (doc) {
@@ -314,13 +314,21 @@ return function (root, x) {
}
function a(e, f) {
addEventListener(root, e, function (e) {
addEventListener(root, e, function (e, n) {
if ('A' == e.target.tagName) {
f(e.target, e);
} else if ('A' == e.target.parentNode.tagName) {
f(e.target.parentNode, e);
} else if (e.target.nextElementSibling && 'A' == e.target.nextElementSibling.tagName) {
f(e.target.nextElementSibling, e, true);
} else {
n = /\bsf-dump-ellipsis\b/.test(e.target.className) ? e.target.parentNode : e.target;
if ((n = n.nextElementSibling) && 'A' == n.tagName) {
if (!/\bsf-dump-toggle\b/.test(n.className)) {
n = n.nextElementSibling || n;
}
f(n, e, true);
}
}
});
};
@@ -363,7 +371,7 @@ return function (root, x) {
if (/\bsf-dump-toggle\b/.test(a.className)) {
e.preventDefault();
if (!toggle(a, isCtrlKey(e))) {
var r = doc.getElementById(a.getAttribute('href').substr(1)),
var r = doc.getElementById(a.getAttribute('href').slice(1)),
s = r.previousSibling,
f = r.parentNode,
t = a.parentNode;
@@ -430,7 +438,7 @@ return function (root, x) {
toggle(a);
}
} else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) {
a = a.substr(1);
a = a.slice(1);
elt.className += ' '+a;
if (/[\[{]$/.test(elt.previousSibling.nodeValue)) {
@@ -469,7 +477,7 @@ return function (root, x) {
return this.current();
}
this.idx = this.idx < (this.nodes.length - 1) ? this.idx + 1 : 0;
return this.current();
},
previous: function () {
@@ -477,7 +485,7 @@ return function (root, x) {
return this.current();
}
this.idx = this.idx > 0 ? this.idx - 1 : (this.nodes.length - 1);
return this.current();
},
isEmpty: function () {
@@ -500,12 +508,17 @@ return function (root, x) {
function showCurrent(state)
{
var currentNode = state.current();
var currentNode = state.current(), currentRect, searchRect;
if (currentNode) {
reveal(currentNode);
highlight(root, currentNode, state.nodes);
if ('scrollIntoView' in currentNode) {
currentNode.scrollIntoView();
currentNode.scrollIntoView(true);
currentRect = currentNode.getBoundingClientRect();
searchRect = search.getBoundingClientRect();
if (currentRect.top < (searchRect.top + searchRect.height)) {
window.scrollBy(0, -(searchRect.top + searchRect.height + 5));
}
}
}
counter.textContent = (state.isEmpty() ? 0 : state.idx + 1) + ' of ' + state.count();
@@ -517,14 +530,10 @@ return function (root, x) {
<input type="text" class="sf-dump-search-input">
<span class="sf-dump-search-count">0 of 0<\/span>
<button type="button" class="sf-dump-search-input-previous" tabindex="-1">
<svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path d="M1683 1331l-166 165q-19 19-45 19t-45-19l-531-531-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z"\/>
<\/svg>
<svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 1331l-166 165q-19 19-45 19t-45-19L896 965l-531 531q-19 19-45 19t-45-19l-166-165q-19-19-19-45.5t19-45.5l742-741q19-19 45-19t45 19l742 741q19 19 19 45.5t-19 45.5z"\/><\/svg>
<\/button>
<button type="button" class="sf-dump-search-input-next" tabindex="-1">
<svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
<path d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"\/>
<\/svg>
<svg viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"\/><\/svg>
<\/button>
';
root.insertBefore(search, root.firstChild);
@@ -560,11 +569,11 @@ return function (root, x) {
"sf-dump-protected",
"sf-dump-private",
].map(xpathHasClass).join(' or ');
var xpathResult = doc.evaluate('.//span[' + classMatches + '][contains(translate(child::text(), ' + xpathString(searchQuery.toUpperCase()) + ', ' + xpathString(searchQuery.toLowerCase()) + '), ' + xpathString(searchQuery.toLowerCase()) + ')]', root, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
while (node = xpathResult.iterateNext()) state.nodes.push(node);
showCurrent(state);
}, 400);
});
@@ -583,6 +592,15 @@ return function (root, x) {
var isSearchActive = !/\bsf-dump-search-hidden\b/.test(search.className);
if ((114 === e.keyCode && !isSearchActive) || (isCtrlKey(e) && 70 === e.keyCode)) {
/* F3 or CMD/CTRL + F */
if (70 === e.keyCode && document.activeElement === searchInput) {
/*
* If CMD/CTRL + F is hit while having focus on search input,
* the user probably meant to trigger browser search instead.
* Let the browser execute its behavior:
*/
return;
}
e.preventDefault();
search.className = search.className.replace(/\bsf-dump-search-hidden\b/, '');
searchInput.focus();
@@ -641,6 +659,7 @@ pre.sf-dump {
display: block;
white-space: pre;
padding: 5px;
overflow: initial !important;
}
pre.sf-dump:after {
content: "";
@@ -655,11 +674,6 @@ pre.sf-dump span {
pre.sf-dump .sf-dump-compact {
display: none;
}
pre.sf-dump abbr {
text-decoration: none;
border: none;
cursor: help;
}
pre.sf-dump a {
text-decoration: none;
cursor: pointer;
@@ -667,6 +681,13 @@ pre.sf-dump a {
outline: none;
color: inherit;
}
pre.sf-dump img {
max-width: 50em;
max-height: 50em;
margin: .5em 0 0 0;
padding: 0;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAHUlEQVQY02O8zAABilCaiQEN0EeA8QuUcX9g3QEAAjcC5piyhyEAAAAASUVORK5CYII=) #D3D3D3;
}
pre.sf-dump .sf-dump-ellipsis {
display: inline-block;
overflow: visible;
@@ -709,14 +730,16 @@ pre.sf-dump code {
border-radius: 3px;
}
pre.sf-dump .sf-dump-search-hidden {
display: none;
display: none !important;
}
pre.sf-dump .sf-dump-search-wrapper {
float: right;
font-size: 0;
white-space: nowrap;
max-width: 100%;
text-align: right;
margin-bottom: 5px;
display: flex;
position: -webkit-sticky;
position: sticky;
top: 5px;
}
pre.sf-dump .sf-dump-search-wrapper > * {
vertical-align: top;
@@ -733,10 +756,11 @@ pre.sf-dump .sf-dump-search-wrapper > input.sf-dump-search-input {
height: 21px;
font-size: 12px;
border-right: none;
width: 140px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
color: #000;
min-width: 15px;
width: 100%;
}
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-next,
pre.sf-dump .sf-dump-search-wrapper > .sf-dump-search-input-previous {
@@ -770,15 +794,36 @@ EOHTML
foreach ($this->styles as $class => $style) {
$line .= 'pre.sf-dump'.('default' === $class ? ', pre.sf-dump' : '').' .sf-dump-'.$class.'{'.$style.'}';
}
$line .= 'pre.sf-dump .sf-dump-ellipsis-note{'.$this->styles['note'].'}';
return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader;
}
/**
* {@inheritdoc}
*/
public function dumpString(Cursor $cursor, $str, $bin, $cut)
{
if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) {
$this->dumpKey($cursor);
$this->line .= $this->style('default', $cursor->attr['img-size'] ?? '', []).' <samp>';
$this->endValue($cursor);
$this->line .= $this->indentPad;
$this->line .= sprintf('<img src="data:%s;base64,%s" /></samp>', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data']));
$this->endValue($cursor);
} else {
parent::dumpString($cursor, $str, $bin, $cut);
}
}
/**
* {@inheritdoc}
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
if (Cursor::HASH_OBJECT === $type) {
$cursor->attr['depth'] = $cursor->depth;
}
parent::enterHash($cursor, $type, $class, false);
if ($cursor->skipChildren) {
@@ -819,7 +864,7 @@ EOHTML
/**
* {@inheritdoc}
*/
protected function style($style, $value, $attr = array())
protected function style($style, $value, $attr = [])
{
if ('' === $value) {
return '';
@@ -837,13 +882,18 @@ EOHTML
}
if ('const' === $style && isset($attr['value'])) {
$style .= sprintf(' title="%s"', esc(is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value'])));
$style .= sprintf(' title="%s"', esc(\is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value'])));
} elseif ('public' === $style) {
$style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property');
} elseif ('str' === $style && 1 < $attr['length']) {
$style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : '');
} elseif ('note' === $style && false !== $c = strrpos($v, '\\')) {
return sprintf('<abbr title="%s" class=sf-dump-%s>%s</abbr>', $v, $style, substr($v, $c + 1));
} elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && false !== $c = strrpos($value, '\\')) {
$style .= ' title=""';
$attr += [
'ellipsis' => \strlen($value) - $c,
'ellipsis-type' => 'note',
'ellipsis-tail' => 1,
];
} elseif ('protected' === $style) {
$style .= ' title="Protected property"';
} elseif ('meta' === $style && isset($attr['title'])) {
@@ -864,7 +914,7 @@ EOHTML
if (!empty($attr['ellipsis-tail'])) {
$tail = \strlen(esc(substr($value, -$attr['ellipsis'], $attr['ellipsis-tail'])));
$v .= sprintf('<span class=sf-dump-ellipsis>%s</span>%s', substr($label, 0, $tail), substr($label, $tail));
$v .= sprintf('<span class=%s>%s</span>%s', $class, substr($label, 0, $tail), substr($label, $tail));
} else {
$v .= $label;
}
@@ -886,13 +936,13 @@ EOHTML
$s .= '">';
}
$s .= isset($map[$c[$i]]) ? $map[$c[$i]] : sprintf('\x%02X', \ord($c[$i]));
$s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i]));
} while (isset($c[++$i]));
return $s.'</span>';
}, $v).'</span>';
if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) {
if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) {
$attr['href'] = $href;
}
if (isset($attr['href'])) {
@@ -914,21 +964,21 @@ EOHTML
if (-1 === $this->lastDepth) {
$this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line;
}
if ($this->headerIsDumped !== (null !== $this->outputStream ? $this->outputStream : $this->lineDumper)) {
if ($this->headerIsDumped !== ($this->outputStream ?? $this->lineDumper)) {
$this->line = $this->getDumpHeader().$this->line;
}
if (-1 === $depth) {
$args = array('"'.$this->dumpId.'"');
$args = ['"'.$this->dumpId.'"'];
if ($this->extraDisplayOptions) {
$args[] = json_encode($this->extraDisplayOptions, JSON_FORCE_OBJECT);
$args[] = json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT);
}
// Replace is for BC
$this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args));
}
$this->lastDepth = $depth;
$this->line = mb_convert_encoding($this->line, 'HTML-ENTITIES', 'UTF-8');
$this->line = mb_encode_numericentity($this->line, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8');
if (-1 === $depth) {
AbstractDumper::dumpLine(0);
@@ -936,19 +986,19 @@ EOHTML
AbstractDumper::dumpLine($depth);
}
private function getSourceLink($file, $line)
private function getSourceLink(string $file, int $line)
{
$options = $this->extraDisplayOptions + $this->displayOptions;
if ($fmt = $options['fileLinkFormat']) {
return \is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line);
return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line);
}
return false;
}
}
function esc($str)
function esc(string $str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
return htmlspecialchars($str, \ENT_QUOTES, 'UTF-8');
}

View File

@@ -30,7 +30,7 @@ class ServerDumper implements DataDumperInterface
* @param DataDumperInterface|null $wrappedDumper A wrapped instance used whenever we failed contacting the server
* @param ContextProviderInterface[] $contextProviders Context providers indexed by context name
*/
public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = array())
public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = [])
{
$this->connection = new Connection($host, $contextProviders);
$this->wrappedDumper = $wrappedDumper;

View File

@@ -17,9 +17,9 @@ namespace Symfony\Component\VarDumper\Exception;
class ThrowingCasterException extends \Exception
{
/**
* @param \Exception $prev The exception thrown from the caster
* @param \Throwable $prev The exception thrown from the caster
*/
public function __construct(\Exception $prev)
public function __construct(\Throwable $prev)
{
parent::__construct('Unexpected '.\get_class($prev).' thrown from a caster: '.$prev->getMessage(), 0, $prev);
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2014-2018 Fabien Potencier
Copyright (c) 2014-2022 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -2,14 +2,14 @@ VarDumper Component
===================
The VarDumper component provides mechanisms for walking through any arbitrary
PHP variable. Built on top, it provides a better `dump()` function that you
can use instead of `var_dump`.
PHP variable. It provides a better `dump()` function that you can use instead
of `var_dump()`.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
* [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

View File

@@ -10,6 +10,10 @@
* file that was distributed with this source code.
*/
if ('cli' !== PHP_SAPI) {
throw new Exception('This script must be run from the command line.');
}
/**
* Starts a dump server to collect and output dumps on a single place with multiple formats support.
*

View File

@@ -38,6 +38,6 @@ if (!function_exists('dd')) {
VarDumper::dump($v);
}
die(1);
exit(1);
}
}

View File

@@ -29,9 +29,9 @@ class Connection
* @param string $host The server host
* @param ContextProviderInterface[] $contextProviders Context providers indexed by context name
*/
public function __construct(string $host, array $contextProviders = array())
public function __construct(string $host, array $contextProviders = [])
{
if (false === strpos($host, '://')) {
if (!str_contains($host, '://')) {
$host = 'tcp://'.$host;
}
@@ -51,20 +51,20 @@ class Connection
return false;
}
$context = array('timestamp' => microtime(true));
$context = ['timestamp' => microtime(true)];
foreach ($this->contextProviders as $name => $provider) {
$context[$name] = $provider->getContext();
}
$context = array_filter($context);
$encodedPayload = base64_encode(serialize(array($data, $context)))."\n";
$encodedPayload = base64_encode(serialize([$data, $context]))."\n";
set_error_handler(array(self::class, 'nullErrorHandler'));
set_error_handler([self::class, 'nullErrorHandler']);
try {
if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) {
return true;
}
if (!$socketIsFresh) {
stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR);
stream_socket_shutdown($this->socket, \STREAM_SHUT_RDWR);
fclose($this->socket);
$this->socket = $this->createSocket();
}
@@ -78,20 +78,18 @@ class Connection
return false;
}
private static function nullErrorHandler($t, $m)
private static function nullErrorHandler(int $t, string $m)
{
// no-op
}
private function createSocket()
{
set_error_handler(array(self::class, 'nullErrorHandler'));
set_error_handler([self::class, 'nullErrorHandler']);
try {
return stream_socket_client($this->host, $errno, $errstr, 3, STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT);
return stream_socket_client($this->host, $errno, $errstr, 3, \STREAM_CLIENT_CONNECT | \STREAM_CLIENT_ASYNC_CONNECT);
} finally {
restore_error_handler();
}
return $socket;
}
}

View File

@@ -30,7 +30,7 @@ class DumpServer
public function __construct(string $host, LoggerInterface $logger = null)
{
if (false === strpos($host, '://')) {
if (!str_contains($host, '://')) {
$host = 'tcp://'.$host;
}
@@ -41,7 +41,7 @@ class DumpServer
public function start(): void
{
if (!$this->socket = stream_socket_server($this->host, $errno, $errstr)) {
throw new \RuntimeException(sprintf('Server start failed on "%s": %s %s.', $this->host, $errstr, $errno));
throw new \RuntimeException(sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno);
}
}
@@ -52,12 +52,12 @@ class DumpServer
}
foreach ($this->getMessages() as $clientId => $message) {
$payload = @unserialize(base64_decode($message), array('allowed_classes' => array(Data::class, Stub::class)));
$payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]);
// Impossible to decode the message, give up.
if (false === $payload) {
if ($this->logger) {
$this->logger->warning('Unable to decode a message from {clientId} client.', array('clientId' => $clientId));
$this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]);
}
continue;
@@ -65,13 +65,13 @@ class DumpServer
if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) {
if ($this->logger) {
$this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', array('clientId' => $clientId));
$this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]);
}
continue;
}
list($data, $context) = $payload;
[$data, $context] = $payload;
$callback($data, $context, $clientId);
}
@@ -84,8 +84,8 @@ class DumpServer
private function getMessages(): iterable
{
$sockets = array((int) $this->socket => $this->socket);
$write = array();
$sockets = [(int) $this->socket => $this->socket];
$write = [];
while (true) {
$read = $sockets;

View File

@@ -19,6 +19,29 @@ use Symfony\Component\VarDumper\Dumper\CliDumper;
*/
trait VarDumperTestTrait
{
/**
* @internal
*/
private $varDumperConfig = [
'casters' => [],
'flags' => null,
];
protected function setUpVarDumper(array $casters, int $flags = null): void
{
$this->varDumperConfig['casters'] = $casters;
$this->varDumperConfig['flags'] = $flags;
}
/**
* @after
*/
protected function tearDownVarDumper(): void
{
$this->varDumperConfig['casters'] = [];
$this->varDumperConfig['flags'] = null;
}
public function assertDumpEquals($expected, $data, $filter = 0, $message = '')
{
$this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message);
@@ -29,24 +52,31 @@ trait VarDumperTestTrait
$this->assertStringMatchesFormat($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message);
}
/**
* @return string|null
*/
protected function getDump($data, $key = null, $filter = 0)
{
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
if (null === $flags = $this->varDumperConfig['flags']) {
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
$flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0;
}
$cloner = new VarCloner();
$cloner->addCasters($this->varDumperConfig['casters']);
$cloner->setMaxItems(-1);
$dumper = new CliDumper(null, null, $flags);
$dumper->setColors(false);
$data = $cloner->cloneVar($data, $filter)->withRefHandles(false);
if (null !== $key && null === $data = $data->seek($key)) {
return;
return null;
}
return rtrim($dumper->dump($data, true));
}
private function prepareExpectation($expected, $filter)
private function prepareExpectation($expected, int $filter): string
{
if (!\is_string($expected)) {
$expected = $this->getDump($expected, null, $filter);

View File

@@ -1,178 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class CasterTest extends TestCase
{
use VarDumperTestTrait;
private $referenceArray = array(
'null' => null,
'empty' => false,
'public' => 'pub',
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0*\0protected" => 'prot',
"\0Foo\0private" => 'priv',
);
/**
* @dataProvider provideFilter
*/
public function testFilter($filter, $expectedDiff, $listedProperties = null)
{
if (null === $listedProperties) {
$filteredArray = Caster::filter($this->referenceArray, $filter);
} else {
$filteredArray = Caster::filter($this->referenceArray, $filter, $listedProperties);
}
$this->assertSame($expectedDiff, array_diff_assoc($this->referenceArray, $filteredArray));
}
public function provideFilter()
{
return array(
array(
0,
array(),
),
array(
Caster::EXCLUDE_PUBLIC,
array(
'null' => null,
'empty' => false,
'public' => 'pub',
),
),
array(
Caster::EXCLUDE_NULL,
array(
'null' => null,
),
),
array(
Caster::EXCLUDE_EMPTY,
array(
'null' => null,
'empty' => false,
),
),
array(
Caster::EXCLUDE_VIRTUAL,
array(
"\0~\0virtual" => 'virt',
),
),
array(
Caster::EXCLUDE_DYNAMIC,
array(
"\0+\0dynamic" => 'dyn',
),
),
array(
Caster::EXCLUDE_PROTECTED,
array(
"\0*\0protected" => 'prot',
),
),
array(
Caster::EXCLUDE_PRIVATE,
array(
"\0Foo\0private" => 'priv',
),
),
array(
Caster::EXCLUDE_VERBOSE,
array(
'public' => 'pub',
"\0*\0protected" => 'prot',
),
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT,
array(
'null' => null,
'empty' => false,
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0Foo\0private" => 'priv',
),
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_VIRTUAL | Caster::EXCLUDE_DYNAMIC,
array(
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_VERBOSE,
$this->referenceArray,
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_EMPTY,
array(
'null' => null,
'empty' => false,
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0*\0protected" => 'prot',
"\0Foo\0private" => 'priv',
),
array('public', 'empty'),
),
array(
Caster::EXCLUDE_VERBOSE | Caster::EXCLUDE_EMPTY | Caster::EXCLUDE_STRICT,
array(
'empty' => false,
),
array('public', 'empty'),
),
);
}
public function testAnonymousClass()
{
$c = eval('return new class extends stdClass { private $foo = "foo"; };');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
stdClass@anonymous {
-foo: "foo"
}
EOTXT
, $c
);
$c = eval('return new class { private $foo = "foo"; };');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
@anonymous {
-foo: "foo"
}
EOTXT
, $c
);
}
}

View File

@@ -1,390 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Caster\DateCaster;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Dany Maillard <danymaillard93b@gmail.com>
*/
class DateCasterTest extends TestCase
{
use VarDumperTestTrait;
/**
* @dataProvider provideDateTimes
*/
public function testDumpDateTime($time, $timezone, $xDate, $xTimestamp)
{
$date = new \DateTime($time, new \DateTimeZone($timezone));
$xDump = <<<EODUMP
DateTime @$xTimestamp {
date: $xDate
}
EODUMP;
$this->assertDumpEquals($xDump, $date);
}
/**
* @dataProvider provideDateTimes
*/
public function testCastDateTime($time, $timezone, $xDate, $xTimestamp, $xInfos)
{
$stub = new Stub();
$date = new \DateTime($time, new \DateTimeZone($timezone));
$cast = DateCaster::castDateTime($date, array('foo' => 'bar'), $stub, false, 0);
$xDump = <<<EODUMP
array:1 [
"\\x00~\\x00date" => $xDate
]
EODUMP;
$this->assertDumpEquals($xDump, $cast);
$xDump = <<<EODUMP
Symfony\Component\VarDumper\Caster\ConstStub {
+type: 1
+class: "$xDate"
+value: "%A$xInfos%A"
+cut: 0
+handle: 0
+refCount: 0
+position: 0
+attr: []
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast["\0~\0date"]);
}
public function provideDateTimes()
{
return array(
array('2017-04-30 00:00:00.000000', 'Europe/Zurich', '2017-04-30 00:00:00.0 Europe/Zurich (+02:00)', 1493503200, 'Sunday, April 30, 2017%Afrom now%ADST On'),
array('2017-12-31 00:00:00.000000', 'Europe/Zurich', '2017-12-31 00:00:00.0 Europe/Zurich (+01:00)', 1514674800, 'Sunday, December 31, 2017%Afrom now%ADST Off'),
array('2017-04-30 00:00:00.000000', '+02:00', '2017-04-30 00:00:00.0 +02:00', 1493503200, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.100000', '+00:00', '2017-04-30 00:00:00.100 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.120000', '+00:00', '2017-04-30 00:00:00.120 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.123000', '+00:00', '2017-04-30 00:00:00.123 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.123400', '+00:00', '2017-04-30 00:00:00.123400 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.123450', '+00:00', '2017-04-30 00:00:00.123450 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
array('2017-04-30 00:00:00.123456', '+00:00', '2017-04-30 00:00:00.123456 +00:00', 1493510400, 'Sunday, April 30, 2017%Afrom now'),
);
}
/**
* @dataProvider provideIntervals
*/
public function testDumpInterval($intervalSpec, $ms, $invert, $expected)
{
if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
$this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
}
$interval = $this->createInterval($intervalSpec, $ms, $invert);
$xDump = <<<EODUMP
DateInterval {
interval: $expected
%A}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $interval);
}
/**
* @dataProvider provideIntervals
*/
public function testDumpIntervalExcludingVerbosity($intervalSpec, $ms, $invert, $expected)
{
if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
$this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
}
$interval = $this->createInterval($intervalSpec, $ms, $invert);
$xDump = <<<EODUMP
DateInterval {
interval: $expected
}
EODUMP;
$this->assertDumpEquals($xDump, $interval, Caster::EXCLUDE_VERBOSE);
}
/**
* @dataProvider provideIntervals
*/
public function testCastInterval($intervalSpec, $ms, $invert, $xInterval, $xSeconds)
{
if ($ms && \PHP_VERSION_ID >= 70200 && version_compare(PHP_VERSION, '7.2.0rc3', '<=')) {
$this->markTestSkipped('Skipped on 7.2 before rc4 because of php bug #75354.');
}
$interval = $this->createInterval($intervalSpec, $ms, $invert);
$stub = new Stub();
$cast = DateCaster::castInterval($interval, array('foo' => 'bar'), $stub, false, Caster::EXCLUDE_VERBOSE);
$xDump = <<<EODUMP
array:1 [
"\\x00~\\x00interval" => $xInterval
]
EODUMP;
$this->assertDumpEquals($xDump, $cast);
if (null === $xSeconds) {
return;
}
$xDump = <<<EODUMP
Symfony\Component\VarDumper\Caster\ConstStub {
+type: 1
+class: "$xInterval"
+value: "$xSeconds"
+cut: 0
+handle: 0
+refCount: 0
+position: 0
+attr: []
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast["\0~\0interval"]);
}
public function provideIntervals()
{
return array(
array('PT0S', 0, 0, '0s', '0s'),
array('PT0S', 0.1, 0, '+ 00:00:00.100', '%is'),
array('PT1S', 0, 0, '+ 00:00:01.0', '%is'),
array('PT2M', 0, 0, '+ 00:02:00.0', '%is'),
array('PT3H', 0, 0, '+ 03:00:00.0', '%ss'),
array('P4D', 0, 0, '+ 4d', '%ss'),
array('P5M', 0, 0, '+ 5m', null),
array('P6Y', 0, 0, '+ 6y', null),
array('P1Y2M3DT4H5M6S', 0, 0, '+ 1y 2m 3d 04:05:06.0', null),
array('PT1M60S', 0, 0, '+ 00:02:00.0', null),
array('PT1H60M', 0, 0, '+ 02:00:00.0', null),
array('P1DT24H', 0, 0, '+ 2d', null),
array('P1M32D', 0, 0, '+ 1m 32d', null),
array('PT0S', 0, 1, '0s', '0s'),
array('PT0S', 0.1, 1, '- 00:00:00.100', '%is'),
array('PT1S', 0, 1, '- 00:00:01.0', '%is'),
array('PT2M', 0, 1, '- 00:02:00.0', '%is'),
array('PT3H', 0, 1, '- 03:00:00.0', '%ss'),
array('P4D', 0, 1, '- 4d', '%ss'),
array('P5M', 0, 1, '- 5m', null),
array('P6Y', 0, 1, '- 6y', null),
array('P1Y2M3DT4H5M6S', 0, 1, '- 1y 2m 3d 04:05:06.0', null),
array('PT1M60S', 0, 1, '- 00:02:00.0', null),
array('PT1H60M', 0, 1, '- 02:00:00.0', null),
array('P1DT24H', 0, 1, '- 2d', null),
array('P1M32D', 0, 1, '- 1m 32d', null),
);
}
/**
* @dataProvider provideTimeZones
*/
public function testDumpTimeZone($timezone, $expected)
{
$timezone = new \DateTimeZone($timezone);
$xDump = <<<EODUMP
DateTimeZone {
timezone: $expected
%A}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $timezone);
}
/**
* @dataProvider provideTimeZones
*/
public function testDumpTimeZoneExcludingVerbosity($timezone, $expected)
{
$timezone = new \DateTimeZone($timezone);
$xDump = <<<EODUMP
DateTimeZone {
timezone: $expected
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $timezone, Caster::EXCLUDE_VERBOSE);
}
/**
* @dataProvider provideTimeZones
*/
public function testCastTimeZone($timezone, $xTimezone, $xRegion)
{
$timezone = new \DateTimeZone($timezone);
$stub = new Stub();
$cast = DateCaster::castTimeZone($timezone, array('foo' => 'bar'), $stub, false, Caster::EXCLUDE_VERBOSE);
$xDump = <<<EODUMP
array:1 [
"\\x00~\\x00timezone" => $xTimezone
]
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast);
$xDump = <<<EODUMP
Symfony\Component\VarDumper\Caster\ConstStub {
+type: 1
+class: "$xTimezone"
+value: "$xRegion"
+cut: 0
+handle: 0
+refCount: 0
+position: 0
+attr: []
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast["\0~\0timezone"]);
}
public function provideTimeZones()
{
$xRegion = \extension_loaded('intl') ? '%s' : '';
return array(
// type 1 (UTC offset)
array('-12:00', '-12:00', ''),
array('+00:00', '+00:00', ''),
array('+14:00', '+14:00', ''),
// type 2 (timezone abbreviation)
array('GMT', '+00:00', ''),
array('a', '+01:00', ''),
array('b', '+02:00', ''),
array('z', '+00:00', ''),
// type 3 (timezone identifier)
array('Africa/Tunis', 'Africa/Tunis (%s:00)', $xRegion),
array('America/Panama', 'America/Panama (%s:00)', $xRegion),
array('Asia/Jerusalem', 'Asia/Jerusalem (%s:00)', $xRegion),
array('Atlantic/Canary', 'Atlantic/Canary (%s:00)', $xRegion),
array('Australia/Perth', 'Australia/Perth (%s:00)', $xRegion),
array('Europe/Zurich', 'Europe/Zurich (%s:00)', $xRegion),
array('Pacific/Tahiti', 'Pacific/Tahiti (%s:00)', $xRegion),
);
}
/**
* @dataProvider providePeriods
*/
public function testDumpPeriod($start, $interval, $end, $options, $expected)
{
$p = new \DatePeriod(new \DateTime($start), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end), $options);
$xDump = <<<EODUMP
DatePeriod {
period: $expected
%A}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $p);
}
/**
* @dataProvider providePeriods
*/
public function testCastPeriod($start, $interval, $end, $options, $xPeriod, $xDates)
{
$p = new \DatePeriod(new \DateTime($start), new \DateInterval($interval), \is_int($end) ? $end : new \DateTime($end), $options);
$stub = new Stub();
$cast = DateCaster::castPeriod($p, array(), $stub, false, 0);
$xDump = <<<EODUMP
array:1 [
"\\x00~\\x00period" => $xPeriod
]
EODUMP;
$this->assertDumpEquals($xDump, $cast);
$xDump = <<<EODUMP
Symfony\Component\VarDumper\Caster\ConstStub {
+type: 1
+class: "$xPeriod"
+value: "%A$xDates%A"
+cut: 0
+handle: 0
+refCount: 0
+position: 0
+attr: []
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast["\0~\0period"]);
}
public function providePeriods()
{
$periods = array(
array('2017-01-01', 'P1D', '2017-01-03', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-03 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02'),
array('2017-01-01', 'P1D', 1, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 2 time/s', '1) 2017-01-01%a2) 2017-01-02'),
array('2017-01-01', 'P1D', '2017-01-04', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-04 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03'),
array('2017-01-01', 'P1D', 2, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 3 time/s', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03'),
array('2017-01-01', 'P1D', '2017-01-05', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-05 00:00:00.0', '1) 2017-01-01%a2) 2017-01-02%a1 more'),
array('2017-01-01', 'P1D', 3, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 4 time/s', '1) 2017-01-01%a2) 2017-01-02%a3) 2017-01-03%a1 more'),
array('2017-01-01', 'P1D', '2017-01-21', 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) to 2017-01-21 00:00:00.0', '1) 2017-01-01%a17 more'),
array('2017-01-01', 'P1D', 19, 0, 'every + 1d, from 2017-01-01 00:00:00.0 (included) recurring 20 time/s', '1) 2017-01-01%a17 more'),
array('2017-01-01 01:00:00', 'P1D', '2017-01-03 01:00:00', 0, 'every + 1d, from 2017-01-01 01:00:00.0 (included) to 2017-01-03 01:00:00.0', '1) 2017-01-01 01:00:00.0%a2) 2017-01-02 01:00:00.0'),
array('2017-01-01 01:00:00', 'P1D', 1, 0, 'every + 1d, from 2017-01-01 01:00:00.0 (included) recurring 2 time/s', '1) 2017-01-01 01:00:00.0%a2) 2017-01-02 01:00:00.0'),
array('2017-01-01', 'P1DT1H', '2017-01-03', 0, 'every + 1d 01:00:00.0, from 2017-01-01 00:00:00.0 (included) to 2017-01-03 00:00:00.0', '1) 2017-01-01 00:00:00.0%a2) 2017-01-02 01:00:00.0'),
array('2017-01-01', 'P1DT1H', 1, 0, 'every + 1d 01:00:00.0, from 2017-01-01 00:00:00.0 (included) recurring 2 time/s', '1) 2017-01-01 00:00:00.0%a2) 2017-01-02 01:00:00.0'),
array('2017-01-01', 'P1D', '2017-01-04', \DatePeriod::EXCLUDE_START_DATE, 'every + 1d, from 2017-01-01 00:00:00.0 (excluded) to 2017-01-04 00:00:00.0', '1) 2017-01-02%a2) 2017-01-03'),
array('2017-01-01', 'P1D', 2, \DatePeriod::EXCLUDE_START_DATE, 'every + 1d, from 2017-01-01 00:00:00.0 (excluded) recurring 2 time/s', '1) 2017-01-02%a2) 2017-01-03'),
);
if (\PHP_VERSION_ID < 70107) {
array_walk($periods, function (&$i) { $i[5] = ''; });
}
return $periods;
}
private function createInterval($intervalSpec, $ms, $invert)
{
$interval = new \DateInterval($intervalSpec);
$interval->f = $ms;
$interval->invert = $invert;
return $interval;
}
}

View File

@@ -1,247 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Caster\ExceptionCaster;
use Symfony\Component\VarDumper\Caster\FrameStub;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
class ExceptionCasterTest extends TestCase
{
use VarDumperTestTrait;
private function getTestException($msg, &$ref = null)
{
return new \Exception(''.$msg);
}
protected function tearDown()
{
ExceptionCaster::$srcContext = 1;
ExceptionCaster::$traceArgs = true;
}
public function testDefaultSettings()
{
$ref = array('foo');
$e = $this->getTestException('foo', $ref);
$expectedDump = <<<'EODUMP'
Exception {
#message: "foo"
#code: 0
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%s%eTests%eCaster%eExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:40 { …}
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testDefaultSettings() {}
%A
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
$this->assertSame(array('foo'), $ref);
}
public function testSeek()
{
$e = $this->getTestException(2);
$expectedDump = <<<'EODUMP'
{
%s%eTests%eCaster%eExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:65 { …}
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testSeek() {}
%A
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $this->getDump($e, 'trace'));
}
public function testNoArgs()
{
$e = $this->getTestException(1);
ExceptionCaster::$traceArgs = false;
$expectedDump = <<<'EODUMP'
Exception {
#message: "1"
#code: 0
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%sExceptionCasterTest.php:28 {
{
return new \Exception(''.$msg);
}
}
%s%eTests%eCaster%eExceptionCasterTest.php:84 { …}
Symfony\Component\VarDumper\Tests\Caster\ExceptionCasterTest->testNoArgs() {}
%A
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
}
public function testNoSrcContext()
{
$e = $this->getTestException(1);
ExceptionCaster::$srcContext = -1;
$expectedDump = <<<'EODUMP'
Exception {
#message: "1"
#code: 0
#file: "%sExceptionCasterTest.php"
#line: 28
trace: {
%s%eTests%eCaster%eExceptionCasterTest.php:28
%s%eTests%eCaster%eExceptionCasterTest.php:%d
%A
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
}
public function testHtmlDump()
{
if (ini_get('xdebug.file_link_format') || get_cfg_var('xdebug.file_link_format')) {
$this->markTestSkipped('A custom file_link_format is defined.');
}
$e = $this->getTestException(1);
ExceptionCaster::$srcContext = -1;
$cloner = new VarCloner();
$cloner->setMaxItems(1);
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dump = $dumper->dump($cloner->cloneVar($e)->withRefHandles(false), true);
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>Exception</span> {<samp>
#<span class=sf-dump-protected title="Protected property">message</span>: "<span class=sf-dump-str>1</span>"
#<span class=sf-dump-protected title="Protected property">code</span>: <span class=sf-dump-num>0</span>
#<span class=sf-dump-protected title="Protected property">file</span>: "<span class=sf-dump-str title="%sExceptionCasterTest.php
%d characters"><span class="sf-dump-ellipsis sf-dump-ellipsis-path">%s%eVarDumper</span><span class=sf-dump-ellipsis>%e</span>Tests%eCaster%eExceptionCasterTest.php</span>"
#<span class=sf-dump-protected title="Protected property">line</span>: <span class=sf-dump-num>28</span>
<span class=sf-dump-meta>trace</span>: {<samp>
<span class=sf-dump-meta title="%sExceptionCasterTest.php
Stack level %d."><span class="sf-dump-ellipsis sf-dump-ellipsis-path">%s%eVarDumper</span><span class=sf-dump-ellipsis>%e</span>Tests%eCaster%eExceptionCasterTest.php</span>:<span class=sf-dump-num>28</span>
&hellip;%d
</samp>}
</samp>}
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
/**
* @requires function Twig\Template::getSourceContext
*/
public function testFrameWithTwig()
{
require_once \dirname(__DIR__).'/Fixtures/Twig.php';
$f = array(
new FrameStub(array(
'file' => \dirname(__DIR__).'/Fixtures/Twig.php',
'line' => 20,
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
)),
new FrameStub(array(
'file' => \dirname(__DIR__).'/Fixtures/Twig.php',
'line' => 21,
'class' => '__TwigTemplate_VarDumperFixture_u75a09',
'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, __FILE__),
)),
);
$expectedDump = <<<'EODUMP'
array:2 [
0 => {
class: "__TwigTemplate_VarDumperFixture_u75a09"
src: {
%sTwig.php:1 {
foo bar
twig source
}
}
}
1 => {
class: "__TwigTemplate_VarDumperFixture_u75a09"
object: __TwigTemplate_VarDumperFixture_u75a09 {
%A
}
src: {
%sExceptionCasterTest.php:2 {
foo bar
twig source
}
}
}
]
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $f);
}
public function testExcludeVerbosity()
{
$e = $this->getTestException('foo');
$expectedDump = <<<'EODUMP'
Exception {
#message: "foo"
#code: 0
#file: "%sExceptionCasterTest.php"
#line: 28
}
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e, Caster::EXCLUDE_VERBOSE);
}
public function testAnonymous()
{
$e = new \Exception(sprintf('Boo "%s" ba.', \get_class(new class('Foo') extends \Exception {
})));
$expectedDump = <<<'EODUMP'
Exception {
#message: "Boo "Exception@anonymous" ba."
#code: 0
#file: "%sExceptionCasterTest.php"
#line: %d
}
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e, Caster::EXCLUDE_VERBOSE);
}
}

View File

@@ -1,48 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\GmpCaster;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
class GmpCasterTest extends TestCase
{
use VarDumperTestTrait;
/**
* @requires extension gmp
*/
public function testCastGmp()
{
$gmpString = gmp_init('1234');
$gmpOctal = gmp_init(010);
$gmp = gmp_init('01101');
$gmpDump = <<<EODUMP
array:1 [
"\\x00~\\x00value" => %s
]
EODUMP;
$this->assertDumpEquals(sprintf($gmpDump, $gmpString), GmpCaster::castGmp($gmpString, array(), new Stub(), false, 0));
$this->assertDumpEquals(sprintf($gmpDump, $gmpOctal), GmpCaster::castGmp($gmpOctal, array(), new Stub(), false, 0));
$this->assertDumpEquals(sprintf($gmpDump, $gmp), GmpCaster::castGmp($gmp, array(), new Stub(), false, 0));
$dump = <<<EODUMP
GMP {
value: 577
}
EODUMP;
$this->assertDumpEquals($dump, $gmp);
}
}

View File

@@ -1,299 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @requires extension intl
*/
class IntlCasterTest extends TestCase
{
use VarDumperTestTrait;
public function testMessageFormatter()
{
$var = new \MessageFormatter('en', 'Hello {name}');
$expected = <<<EOTXT
MessageFormatter {
locale: "en"
pattern: "Hello {name}"
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastNumberFormatter()
{
$var = new \NumberFormatter('en', \NumberFormatter::DECIMAL);
$expectedLocale = $var->getLocale();
$expectedPattern = $var->getPattern();
$expectedAttribute1 = $var->getAttribute(\NumberFormatter::PARSE_INT_ONLY);
$expectedAttribute2 = $var->getAttribute(\NumberFormatter::GROUPING_USED);
$expectedAttribute3 = $var->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN);
$expectedAttribute4 = $var->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS);
$expectedAttribute5 = $var->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS);
$expectedAttribute6 = $var->getAttribute(\NumberFormatter::INTEGER_DIGITS);
$expectedAttribute7 = $var->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS);
$expectedAttribute8 = $var->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS);
$expectedAttribute9 = $var->getAttribute(\NumberFormatter::FRACTION_DIGITS);
$expectedAttribute10 = $var->getAttribute(\NumberFormatter::MULTIPLIER);
$expectedAttribute11 = $var->getAttribute(\NumberFormatter::GROUPING_SIZE);
$expectedAttribute12 = $var->getAttribute(\NumberFormatter::ROUNDING_MODE);
$expectedAttribute13 = number_format($var->getAttribute(\NumberFormatter::ROUNDING_INCREMENT), 1);
$expectedAttribute14 = $var->getAttribute(\NumberFormatter::FORMAT_WIDTH);
$expectedAttribute15 = $var->getAttribute(\NumberFormatter::PADDING_POSITION);
$expectedAttribute16 = $var->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE);
$expectedAttribute17 = $var->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED);
$expectedAttribute18 = $var->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS);
$expectedAttribute19 = $var->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS);
$expectedAttribute20 = $var->getAttribute(\NumberFormatter::LENIENT_PARSE);
$expectedTextAttribute1 = $var->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX);
$expectedTextAttribute2 = $var->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX);
$expectedTextAttribute3 = $var->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX);
$expectedTextAttribute4 = $var->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX);
$expectedTextAttribute5 = $var->getTextAttribute(\NumberFormatter::PADDING_CHARACTER);
$expectedTextAttribute6 = $var->getTextAttribute(\NumberFormatter::CURRENCY_CODE);
$expectedTextAttribute7 = $var->getTextAttribute(\NumberFormatter::DEFAULT_RULESET) ? 'true' : 'false';
$expectedTextAttribute8 = $var->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS) ? 'true' : 'false';
$expectedSymbol1 = $var->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL);
$expectedSymbol2 = $var->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL);
$expectedSymbol3 = $var->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL);
$expectedSymbol4 = $var->getSymbol(\NumberFormatter::PERCENT_SYMBOL);
$expectedSymbol5 = $var->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL);
$expectedSymbol6 = $var->getSymbol(\NumberFormatter::DIGIT_SYMBOL);
$expectedSymbol7 = $var->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL);
$expectedSymbol8 = $var->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL);
$expectedSymbol9 = $var->getSymbol(\NumberFormatter::CURRENCY_SYMBOL);
$expectedSymbol10 = $var->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL);
$expectedSymbol11 = $var->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL);
$expectedSymbol12 = $var->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL);
$expectedSymbol13 = $var->getSymbol(\NumberFormatter::PERMILL_SYMBOL);
$expectedSymbol14 = $var->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL);
$expectedSymbol15 = $var->getSymbol(\NumberFormatter::INFINITY_SYMBOL);
$expectedSymbol16 = $var->getSymbol(\NumberFormatter::NAN_SYMBOL);
$expectedSymbol17 = $var->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL);
$expectedSymbol18 = $var->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL);
$expected = <<<EOTXT
NumberFormatter {
locale: "$expectedLocale"
pattern: "$expectedPattern"
attributes: {
PARSE_INT_ONLY: $expectedAttribute1
GROUPING_USED: $expectedAttribute2
DECIMAL_ALWAYS_SHOWN: $expectedAttribute3
MAX_INTEGER_DIGITS: $expectedAttribute4
MIN_INTEGER_DIGITS: $expectedAttribute5
INTEGER_DIGITS: $expectedAttribute6
MAX_FRACTION_DIGITS: $expectedAttribute7
MIN_FRACTION_DIGITS: $expectedAttribute8
FRACTION_DIGITS: $expectedAttribute9
MULTIPLIER: $expectedAttribute10
GROUPING_SIZE: $expectedAttribute11
ROUNDING_MODE: $expectedAttribute12
ROUNDING_INCREMENT: $expectedAttribute13
FORMAT_WIDTH: $expectedAttribute14
PADDING_POSITION: $expectedAttribute15
SECONDARY_GROUPING_SIZE: $expectedAttribute16
SIGNIFICANT_DIGITS_USED: $expectedAttribute17
MIN_SIGNIFICANT_DIGITS: $expectedAttribute18
MAX_SIGNIFICANT_DIGITS: $expectedAttribute19
LENIENT_PARSE: $expectedAttribute20
}
text_attributes: {
POSITIVE_PREFIX: "$expectedTextAttribute1"
POSITIVE_SUFFIX: "$expectedTextAttribute2"
NEGATIVE_PREFIX: "$expectedTextAttribute3"
NEGATIVE_SUFFIX: "$expectedTextAttribute4"
PADDING_CHARACTER: "$expectedTextAttribute5"
CURRENCY_CODE: "$expectedTextAttribute6"
DEFAULT_RULESET: $expectedTextAttribute7
PUBLIC_RULESETS: $expectedTextAttribute8
}
symbols: {
DECIMAL_SEPARATOR_SYMBOL: "$expectedSymbol1"
GROUPING_SEPARATOR_SYMBOL: "$expectedSymbol2"
PATTERN_SEPARATOR_SYMBOL: "$expectedSymbol3"
PERCENT_SYMBOL: "$expectedSymbol4"
ZERO_DIGIT_SYMBOL: "$expectedSymbol5"
DIGIT_SYMBOL: "$expectedSymbol6"
MINUS_SIGN_SYMBOL: "$expectedSymbol7"
PLUS_SIGN_SYMBOL: "$expectedSymbol8"
CURRENCY_SYMBOL: "$expectedSymbol9"
INTL_CURRENCY_SYMBOL: "$expectedSymbol10"
MONETARY_SEPARATOR_SYMBOL: "$expectedSymbol11"
EXPONENTIAL_SYMBOL: "$expectedSymbol12"
PERMILL_SYMBOL: "$expectedSymbol13"
PAD_ESCAPE_SYMBOL: "$expectedSymbol14"
INFINITY_SYMBOL: "$expectedSymbol15"
NAN_SYMBOL: "$expectedSymbol16"
SIGNIFICANT_DIGIT_SYMBOL: "$expectedSymbol17"
MONETARY_GROUPING_SEPARATOR_SYMBOL: "$expectedSymbol18"
}
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastIntlTimeZoneWithDST()
{
$var = \IntlTimeZone::createTimeZone('America/Los_Angeles');
$expectedDisplayName = $var->getDisplayName();
$expectedDSTSavings = $var->getDSTSavings();
$expectedID = $var->getID();
$expectedRawOffset = $var->getRawOffset();
$expected = <<<EOTXT
IntlTimeZone {
display_name: "$expectedDisplayName"
id: "$expectedID"
raw_offset: $expectedRawOffset
dst_savings: $expectedDSTSavings
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastIntlTimeZoneWithoutDST()
{
$var = \IntlTimeZone::createTimeZone('Asia/Bangkok');
$expectedDisplayName = $var->getDisplayName();
$expectedID = $var->getID();
$expectedRawOffset = $var->getRawOffset();
$expected = <<<EOTXT
IntlTimeZone {
display_name: "$expectedDisplayName"
id: "$expectedID"
raw_offset: $expectedRawOffset
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastIntlCalendar()
{
$var = \IntlCalendar::createInstance('America/Los_Angeles', 'en');
$expectedType = $var->getType();
$expectedFirstDayOfWeek = $var->getFirstDayOfWeek();
$expectedMinimalDaysInFirstWeek = $var->getMinimalDaysInFirstWeek();
$expectedRepeatedWallTimeOption = $var->getRepeatedWallTimeOption();
$expectedSkippedWallTimeOption = $var->getSkippedWallTimeOption();
$expectedTime = $var->getTime().'.0';
$expectedInDaylightTime = $var->inDaylightTime() ? 'true' : 'false';
$expectedIsLenient = $var->isLenient() ? 'true' : 'false';
$expectedTimeZone = $var->getTimeZone();
$expectedTimeZoneDisplayName = $expectedTimeZone->getDisplayName();
$expectedTimeZoneID = $expectedTimeZone->getID();
$expectedTimeZoneRawOffset = $expectedTimeZone->getRawOffset();
$expectedTimeZoneDSTSavings = $expectedTimeZone->getDSTSavings();
$expected = <<<EOTXT
IntlGregorianCalendar {
type: "$expectedType"
first_day_of_week: $expectedFirstDayOfWeek
minimal_days_in_first_week: $expectedMinimalDaysInFirstWeek
repeated_wall_time_option: $expectedRepeatedWallTimeOption
skipped_wall_time_option: $expectedSkippedWallTimeOption
time: $expectedTime
in_daylight_time: $expectedInDaylightTime
is_lenient: $expectedIsLenient
time_zone: IntlTimeZone {
display_name: "$expectedTimeZoneDisplayName"
id: "$expectedTimeZoneID"
raw_offset: $expectedTimeZoneRawOffset
dst_savings: $expectedTimeZoneDSTSavings
}
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastDateFormatter()
{
$var = new \IntlDateFormatter('en', \IntlDateFormatter::TRADITIONAL, \IntlDateFormatter::TRADITIONAL);
$expectedLocale = $var->getLocale();
$expectedPattern = $var->getPattern();
$expectedCalendar = $var->getCalendar();
$expectedTimeZoneId = $var->getTimeZoneId();
$expectedTimeType = $var->getTimeType();
$expectedDateType = $var->getDateType();
$expectedCalendarObject = $var->getCalendarObject();
$expectedCalendarObjectType = $expectedCalendarObject->getType();
$expectedCalendarObjectFirstDayOfWeek = $expectedCalendarObject->getFirstDayOfWeek();
$expectedCalendarObjectMinimalDaysInFirstWeek = $expectedCalendarObject->getMinimalDaysInFirstWeek();
$expectedCalendarObjectRepeatedWallTimeOption = $expectedCalendarObject->getRepeatedWallTimeOption();
$expectedCalendarObjectSkippedWallTimeOption = $expectedCalendarObject->getSkippedWallTimeOption();
$expectedCalendarObjectTime = $expectedCalendarObject->getTime().'.0';
$expectedCalendarObjectInDaylightTime = $expectedCalendarObject->inDaylightTime() ? 'true' : 'false';
$expectedCalendarObjectIsLenient = $expectedCalendarObject->isLenient() ? 'true' : 'false';
$expectedCalendarObjectTimeZone = $expectedCalendarObject->getTimeZone();
$expectedCalendarObjectTimeZoneDisplayName = $expectedCalendarObjectTimeZone->getDisplayName();
$expectedCalendarObjectTimeZoneID = $expectedCalendarObjectTimeZone->getID();
$expectedCalendarObjectTimeZoneRawOffset = $expectedCalendarObjectTimeZone->getRawOffset();
$expectedCalendarObjectTimeZoneDSTSavings = $expectedCalendarObjectTimeZone->getDSTSavings();
$expectedTimeZone = $var->getTimeZone();
$expectedTimeZoneDisplayName = $expectedTimeZone->getDisplayName();
$expectedTimeZoneID = $expectedTimeZone->getID();
$expectedTimeZoneRawOffset = $expectedTimeZone->getRawOffset();
$expectedTimeZoneDSTSavings = $expectedTimeZone->getDSTSavings();
$expected = <<<EOTXT
IntlDateFormatter {
locale: "$expectedLocale"
pattern: "$expectedPattern"
calendar: $expectedCalendar
time_zone_id: "$expectedTimeZoneId"
time_type: $expectedTimeType
date_type: $expectedDateType
calendar_object: IntlGregorianCalendar {
type: "$expectedCalendarObjectType"
first_day_of_week: $expectedCalendarObjectFirstDayOfWeek
minimal_days_in_first_week: $expectedCalendarObjectMinimalDaysInFirstWeek
repeated_wall_time_option: $expectedCalendarObjectRepeatedWallTimeOption
skipped_wall_time_option: $expectedCalendarObjectSkippedWallTimeOption
time: $expectedCalendarObjectTime
in_daylight_time: $expectedCalendarObjectInDaylightTime
is_lenient: $expectedCalendarObjectIsLenient
time_zone: IntlTimeZone {
display_name: "$expectedCalendarObjectTimeZoneDisplayName"
id: "$expectedCalendarObjectTimeZoneID"
raw_offset: $expectedCalendarObjectTimeZoneRawOffset
dst_savings: $expectedCalendarObjectTimeZoneDSTSavings
}
}
time_zone: IntlTimeZone {
display_name: "$expectedTimeZoneDisplayName"
id: "$expectedTimeZoneID"
raw_offset: $expectedTimeZoneRawOffset
dst_savings: $expectedTimeZoneDSTSavings
}
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
}

View File

@@ -1,93 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Jan Schädlich <jan.schaedlich@sensiolabs.de>
*/
class MemcachedCasterTest extends TestCase
{
use VarDumperTestTrait;
public function testCastMemcachedWithDefaultOptions()
{
if (!class_exists('Memcached')) {
$this->markTestSkipped('Memcached not available');
}
$var = new \Memcached();
$var->addServer('127.0.0.1', 11211);
$var->addServer('127.0.0.2', 11212);
$expected = <<<EOTXT
Memcached {
servers: array:2 [
0 => array:3 [
"host" => "127.0.0.1"
"port" => 11211
"type" => "TCP"
]
1 => array:3 [
"host" => "127.0.0.2"
"port" => 11212
"type" => "TCP"
]
]
options: {}
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testCastMemcachedWithCustomOptions()
{
if (!class_exists('Memcached')) {
$this->markTestSkipped('Memcached not available');
}
$var = new \Memcached();
$var->addServer('127.0.0.1', 11211);
$var->addServer('127.0.0.2', 11212);
// set a subset of non default options to test boolean, string and integer output
$var->setOption(\Memcached::OPT_COMPRESSION, false);
$var->setOption(\Memcached::OPT_PREFIX_KEY, 'pre');
$var->setOption(\Memcached::OPT_DISTRIBUTION, \Memcached::DISTRIBUTION_CONSISTENT);
$expected = <<<'EOTXT'
Memcached {
servers: array:2 [
0 => array:3 [
"host" => "127.0.0.1"
"port" => 11211
"type" => "TCP"
]
1 => array:3 [
"host" => "127.0.0.2"
"port" => 11212
"type" => "TCP"
]
]
options: {
OPT_COMPRESSION: false
OPT_PREFIX_KEY: "pre"
OPT_DISTRIBUTION: 1
}
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
}

View File

@@ -1,64 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\PdoCaster;
use Symfony\Component\VarDumper\Cloner\Stub;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class PdoCasterTest extends TestCase
{
use VarDumperTestTrait;
/**
* @requires extension pdo_sqlite
*/
public function testCastPdo()
{
$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array($pdo)));
$cast = PdoCaster::castPdo($pdo, array(), new Stub(), false);
$this->assertInstanceOf('Symfony\Component\VarDumper\Caster\EnumStub', $cast["\0~\0attributes"]);
$attr = $cast["\0~\0attributes"] = $cast["\0~\0attributes"]->value;
$this->assertInstanceOf('Symfony\Component\VarDumper\Caster\ConstStub', $attr['CASE']);
$this->assertSame('NATURAL', $attr['CASE']->class);
$this->assertSame('BOTH', $attr['DEFAULT_FETCH_MODE']->class);
$xDump = <<<'EODUMP'
array:2 [
"\x00~\x00inTransaction" => false
"\x00~\x00attributes" => array:9 [
"CASE" => NATURAL
"ERRMODE" => SILENT
"PERSISTENT" => false
"DRIVER_NAME" => "sqlite"
"ORACLE_NULLS" => NATURAL
"CLIENT_VERSION" => "%s"
"SERVER_VERSION" => "%s"
"STATEMENT_CLASS" => array:%d [
0 => "PDOStatement"%A
]
"DEFAULT_FETCH_MODE" => BOTH
]
]
EODUMP;
$this->assertDumpMatchesFormat($xDump, $cast);
}
}

View File

@@ -1,70 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Nicolas Grekas <p@tchwork.com>
* @requires extension redis
*/
class RedisCasterTest extends TestCase
{
use VarDumperTestTrait;
public function testNotConnected()
{
$redis = new \Redis();
$xCast = <<<'EODUMP'
Redis {
isConnected: false
}
EODUMP;
$this->assertDumpMatchesFormat($xCast, $redis);
}
public function testConnected()
{
$redis = new \Redis();
if (!@$redis->connect('127.0.0.1')) {
$e = error_get_last();
self::markTestSkipped($e['message']);
}
$xCast = <<<'EODUMP'
Redis {%A
isConnected: true
host: "127.0.0.1"
port: 6379
auth: null
mode: ATOMIC
dbNum: 0
timeout: 0.0
lastError: null
persistentId: null
options: {
TCP_KEEPALIVE: 0
READ_TIMEOUT: 0.0
COMPRESSION: NONE
SERIALIZER: NONE
PREFIX: null
SCAN: NORETRY
}
}
EODUMP;
$this->assertDumpMatchesFormat($xCast, $redis);
}
}

View File

@@ -1,254 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
use Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo;
use Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class ReflectionCasterTest extends TestCase
{
use VarDumperTestTrait;
public function testReflectionCaster()
{
$var = new \ReflectionClass('ReflectionClass');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionClass {
+name: "ReflectionClass"
%Aimplements: array:%d [
0 => "Reflector"
%A]
constants: array:3 [
"IS_IMPLICIT_ABSTRACT" => 16
"IS_EXPLICIT_ABSTRACT" => 32
"IS_FINAL" => %d
]
properties: array:%d [
"name" => ReflectionProperty {
%A +name: "name"
+class: "ReflectionClass"
%A modifiers: "public"
}
%A]
methods: array:%d [
%A
"export" => ReflectionMethod {
+name: "export"
+class: "ReflectionClass"
%A parameters: {
$%s: ReflectionParameter {
%A position: 0
%A
}
EOTXT
, $var
);
}
public function testClosureCaster()
{
$a = $b = 123;
$var = function ($x) use ($a, &$b) {};
$this->assertDumpMatchesFormat(
<<<'EOTXT'
Closure($x) {
%Aparameters: {
$x: {}
}
use: {
$a: 123
$b: & 123
}
file: "%sReflectionCasterTest.php"
line: "68 to 68"
}
EOTXT
, $var
);
}
public function testFromCallableClosureCaster()
{
if (\defined('HHVM_VERSION_ID')) {
$this->markTestSkipped('Not for HHVM.');
}
$var = array(
(new \ReflectionMethod($this, __FUNCTION__))->getClosure($this),
(new \ReflectionMethod(__CLASS__, 'tearDownAfterClass'))->getClosure(),
);
$this->assertDumpMatchesFormat(
<<<EOTXT
array:2 [
0 => Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest::testFromCallableClosureCaster() {
this: Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest { …}
file: "%sReflectionCasterTest.php"
line: "%d to %d"
}
1 => %sTestCase::tearDownAfterClass() {
file: "%sTestCase.php"
line: "%d to %d"
}
]
EOTXT
, $var
);
}
public function testClosureCasterExcludingVerbosity()
{
$var = function &($a = 5) {};
$this->assertDumpEquals('Closure&($a = 5) { …6}', $var, Caster::EXCLUDE_VERBOSE);
}
public function testReflectionParameter()
{
$var = new \ReflectionParameter(__NAMESPACE__.'\reflectionParameterFixture', 0);
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionParameter {
+name: "arg1"
position: 0
typeHint: "Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass"
default: null
}
EOTXT
, $var
);
}
public function testReflectionParameterScalar()
{
$f = eval('return function (int $a) {};');
$var = new \ReflectionParameter($f, 0);
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionParameter {
+name: "a"
position: 0
typeHint: "int"
}
EOTXT
, $var
);
}
public function testReturnType()
{
$f = eval('return function ():int {};');
$line = __LINE__ - 1;
$this->assertDumpMatchesFormat(
<<<EOTXT
Closure(): int {
returnType: "int"
class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest"
this: Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest { …}
file: "%sReflectionCasterTest.php($line) : eval()'d code"
line: "1 to 1"
}
EOTXT
, $f
);
}
public function testGenerator()
{
if (\extension_loaded('xdebug')) {
$this->markTestSkipped('xdebug is active');
}
$generator = new GeneratorDemo();
$generator = $generator->baz();
$expectedDump = <<<'EODUMP'
Generator {
this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …}
executing: {
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {
%sGeneratorDemo.php:14 {
{
yield from bar();
}
}
}
}
closed: false
}
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $generator);
foreach ($generator as $v) {
break;
}
$expectedDump = <<<'EODUMP'
array:2 [
0 => ReflectionGenerator {
this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …}
trace: {
%s%eTests%eFixtures%eGeneratorDemo.php:9 {
{
yield 1;
}
}
%s%eTests%eFixtures%eGeneratorDemo.php:20 { …}
%s%eTests%eFixtures%eGeneratorDemo.php:14 { …}
}
closed: false
}
1 => Generator {
executing: {
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() {
%sGeneratorDemo.php:10 {
yield 1;
}
}
}
}
closed: false
}
]
EODUMP;
$r = new \ReflectionGenerator($generator);
$this->assertDumpMatchesFormat($expectedDump, array($r, $r->getExecutingGenerator()));
foreach ($generator as $v) {
}
$expectedDump = <<<'EODUMP'
Generator {
closed: true
}
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $generator);
}
}
function reflectionParameterFixture(NotLoadableClass $arg1 = null, $arg2)
{
}

View File

@@ -1,207 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class SplCasterTest extends TestCase
{
use VarDumperTestTrait;
public function getCastFileInfoTests()
{
return array(
array(__FILE__, <<<'EOTXT'
SplFileInfo {
%Apath: "%sCaster"
filename: "SplCasterTest.php"
basename: "SplCasterTest.php"
pathname: "%sSplCasterTest.php"
extension: "php"
realPath: "%sSplCasterTest.php"
aTime: %s-%s-%d %d:%d:%d
mTime: %s-%s-%d %d:%d:%d
cTime: %s-%s-%d %d:%d:%d
inode: %d
size: %d
perms: 0%d
owner: %d
group: %d
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
%A}
EOTXT
),
array('https://google.com/about', <<<'EOTXT'
SplFileInfo {
%Apath: "https://google.com"
filename: "about"
basename: "about"
pathname: "https://google.com/about"
extension: ""
realPath: false
%A}
EOTXT
),
);
}
/** @dataProvider getCastFileInfoTests */
public function testCastFileInfo($file, $dump)
{
$this->assertDumpMatchesFormat($dump, new \SplFileInfo($file));
}
public function testCastFileObject()
{
$var = new \SplFileObject(__FILE__);
$var->setFlags(\SplFileObject::DROP_NEW_LINE | \SplFileObject::SKIP_EMPTY);
$dump = <<<'EOTXT'
SplFileObject {
%Apath: "%sCaster"
filename: "SplCasterTest.php"
basename: "SplCasterTest.php"
pathname: "%sSplCasterTest.php"
extension: "php"
realPath: "%sSplCasterTest.php"
aTime: %s-%s-%d %d:%d:%d
mTime: %s-%s-%d %d:%d:%d
cTime: %s-%s-%d %d:%d:%d
inode: %d
size: %d
perms: 0%d
owner: %d
group: %d
type: "file"
writable: true
readable: true
executable: false
file: true
dir: false
link: false
%AcsvControl: array:%d [
0 => ","
1 => """
%A]
flags: DROP_NEW_LINE|SKIP_EMPTY
maxLineLen: 0
fstat: array:26 [
"dev" => %d
"ino" => %d
"nlink" => %d
"rdev" => 0
"blksize" => %i
"blocks" => %i
…20
]
eof: false
key: 0
}
EOTXT;
$this->assertDumpMatchesFormat($dump, $var);
}
/**
* @dataProvider provideCastSplDoublyLinkedList
*/
public function testCastSplDoublyLinkedList($modeValue, $modeDump)
{
$var = new \SplDoublyLinkedList();
$var->setIteratorMode($modeValue);
$dump = <<<EOTXT
SplDoublyLinkedList {
%Amode: $modeDump
dllist: []
}
EOTXT;
$this->assertDumpMatchesFormat($dump, $var);
}
public function provideCastSplDoublyLinkedList()
{
return array(
array(\SplDoublyLinkedList::IT_MODE_FIFO, 'IT_MODE_FIFO | IT_MODE_KEEP'),
array(\SplDoublyLinkedList::IT_MODE_LIFO, 'IT_MODE_LIFO | IT_MODE_KEEP'),
array(\SplDoublyLinkedList::IT_MODE_FIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_FIFO | IT_MODE_DELETE'),
array(\SplDoublyLinkedList::IT_MODE_LIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_LIFO | IT_MODE_DELETE'),
);
}
public function testCastObjectStorageIsntModified()
{
$var = new \SplObjectStorage();
$var->attach(new \stdClass());
$var->rewind();
$current = $var->current();
$this->assertDumpMatchesFormat('%A', $var);
$this->assertSame($current, $var->current());
}
public function testCastObjectStorageDumpsInfo()
{
$var = new \SplObjectStorage();
$var->attach(new \stdClass(), new \DateTime());
$this->assertDumpMatchesFormat('%ADateTime%A', $var);
}
public function testCastArrayObject()
{
$var = new \ArrayObject(array(123));
$var->foo = 234;
$expected = <<<EOTXT
ArrayObject {
+"foo": 234
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
iteratorClass: "ArrayIterator"
storage: array:1 [
0 => 123
]
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
public function testArrayIterator()
{
$var = new MyArrayIterator(array(234));
$expected = <<<EOTXT
Symfony\Component\VarDumper\Tests\Caster\MyArrayIterator {
-foo: 123
flag::STD_PROP_LIST: false
flag::ARRAY_AS_PROPS: false
storage: array:1 [
0 => 234
]
}
EOTXT;
$this->assertDumpEquals($expected, $var);
}
}
class MyArrayIterator extends \ArrayIterator
{
private $foo = 123;
}

View File

@@ -1,213 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\ArgsStub;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Component\VarDumper\Caster\LinkStub;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
use Symfony\Component\VarDumper\Tests\Fixtures\FooInterface;
class StubCasterTest extends TestCase
{
use VarDumperTestTrait;
public function testArgsStubWithDefaults($foo = 234, $bar = 456)
{
$args = array(new ArgsStub(array(123), __FUNCTION__, __CLASS__));
$expectedDump = <<<'EODUMP'
array:1 [
0 => {
$foo: 123
}
]
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $args);
}
public function testArgsStubWithExtraArgs($foo = 234)
{
$args = array(new ArgsStub(array(123, 456), __FUNCTION__, __CLASS__));
$expectedDump = <<<'EODUMP'
array:1 [
0 => {
$foo: 123
...: {
456
}
}
]
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $args);
}
public function testArgsStubNoParamWithExtraArgs()
{
$args = array(new ArgsStub(array(123), __FUNCTION__, __CLASS__));
$expectedDump = <<<'EODUMP'
array:1 [
0 => {
123
}
]
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $args);
}
public function testArgsStubWithClosure()
{
$args = array(new ArgsStub(array(123), '{closure}', null));
$expectedDump = <<<'EODUMP'
array:1 [
0 => {
123
}
]
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $args);
}
public function testLinkStub()
{
$var = array(new LinkStub(__CLASS__, 0, __FILE__));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dumper->setDisplayOptions(array('fileLinkFormat' => '%f:%l'));
$dump = $dumper->dump($cloner->cloneVar($var), true);
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="%sStubCasterTest.php:0" rel="noopener noreferrer"><span class=sf-dump-str title="55 characters">Symfony\Component\VarDumper\Tests\Caster\StubCasterTest</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
public function testLinkStubWithNoFileLink()
{
$var = array(new LinkStub('example.com', 0, 'http://example.com'));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dumper->setDisplayOptions(array('fileLinkFormat' => '%f:%l'));
$dump = $dumper->dump($cloner->cloneVar($var), true);
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="http://example.com" target="_blank" rel="noopener noreferrer"><span class=sf-dump-str title="11 characters">example.com</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
public function testClassStub()
{
$var = array(new ClassStub('hello', array(FooInterface::class, 'foo')));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dump = $dumper->dump($cloner->cloneVar($var), true, array('fileLinkFormat' => '%f:%l'));
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="%sFooInterface.php:10" rel="noopener noreferrer"><span class=sf-dump-str title="39 characters">hello(?stdClass $a, stdClass $b = null)</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
public function testClassStubWithNotExistingClass()
{
$var = array(new ClassStub(NotExisting::class));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dump = $dumper->dump($cloner->cloneVar($var), true);
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<span class=sf-dump-str title="Symfony\Component\VarDumper\Tests\Caster\NotExisting
52 characters"><span class="sf-dump-ellipsis sf-dump-ellipsis-class">Symfony\Component\VarDumper\Tests\Caster</span><span class=sf-dump-ellipsis>\</span>NotExisting</span>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
public function testClassStubWithNotExistingMethod()
{
$var = array(new ClassStub('hello', array(FooInterface::class, 'missing')));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dump = $dumper->dump($cloner->cloneVar($var), true, array('fileLinkFormat' => '%f:%l'));
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="%sFooInterface.php:5" rel="noopener noreferrer"><span class=sf-dump-str title="5 characters">hello</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
public function testClassStubWithAnonymousClass()
{
$var = array(new ClassStub(\get_class(new class() extends \Exception {
})));
$cloner = new VarCloner();
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$dump = $dumper->dump($cloner->cloneVar($var), true, array('fileLinkFormat' => '%f:%l'));
$expectedDump = <<<'EODUMP'
<foo></foo><bar><span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => "<a href="%sStubCasterTest.php:195" rel="noopener noreferrer"><span class=sf-dump-str title="19 characters">Exception@anonymous</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
}

View File

@@ -1,248 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
/**
* @author Baptiste Clavié <clavie.b@gmail.com>
*/
class XmlReaderCasterTest extends TestCase
{
use VarDumperTestTrait;
/** @var \XmlReader */
private $reader;
protected function setUp()
{
$this->reader = new \XmlReader();
$this->reader->open(__DIR__.'/../Fixtures/xml_reader.xml');
}
protected function tearDown()
{
$this->reader->close();
}
public function testParserProperty()
{
$this->reader->setParserProperty(\XMLReader::SUBST_ENTITIES, true);
$expectedDump = <<<'EODUMP'
XMLReader {
+nodeType: NONE
parserProperties: {
SUBST_ENTITIES: true
…3
}
…12
}
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $this->reader);
}
/**
* @dataProvider provideNodes
*/
public function testNodes($seek, $expectedDump)
{
while ($seek--) {
$this->reader->read();
}
$this->assertDumpMatchesFormat($expectedDump, $this->reader);
}
public function provideNodes()
{
return array(
array(0, <<<'EODUMP'
XMLReader {
+nodeType: NONE
…13
}
EODUMP
),
array(1, <<<'EODUMP'
XMLReader {
+localName: "foo"
+nodeType: ELEMENT
+baseURI: "%sxml_reader.xml"
…11
}
EODUMP
),
array(2, <<<'EODUMP'
XMLReader {
+localName: "#text"
+nodeType: SIGNIFICANT_WHITESPACE
+depth: 1
+value: """
\n
"""
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(3, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: ELEMENT
+depth: 1
+baseURI: "%sxml_reader.xml"
…10
}
EODUMP
),
array(4, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: END_ELEMENT
+depth: 1
+baseURI: "%sxml_reader.xml"
…10
}
EODUMP
),
array(6, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: ELEMENT
+depth: 1
+isEmptyElement: true
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(9, <<<'EODUMP'
XMLReader {
+localName: "#text"
+nodeType: TEXT
+depth: 2
+value: "With text"
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(12, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: ELEMENT
+depth: 1
+attributeCount: 2
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(13, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: END_ELEMENT
+depth: 1
+baseURI: "%sxml_reader.xml"
…10
}
EODUMP
),
array(15, <<<'EODUMP'
XMLReader {
+localName: "bar"
+nodeType: ELEMENT
+depth: 1
+attributeCount: 1
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(16, <<<'EODUMP'
XMLReader {
+localName: "#text"
+nodeType: SIGNIFICANT_WHITESPACE
+depth: 2
+value: """
\n
"""
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(17, <<<'EODUMP'
XMLReader {
+localName: "baz"
+prefix: "baz"
+nodeType: ELEMENT
+depth: 2
+namespaceURI: "http://symfony.com"
+baseURI: "%sxml_reader.xml"
…8
}
EODUMP
),
array(18, <<<'EODUMP'
XMLReader {
+localName: "baz"
+prefix: "baz"
+nodeType: END_ELEMENT
+depth: 2
+namespaceURI: "http://symfony.com"
+baseURI: "%sxml_reader.xml"
…8
}
EODUMP
),
array(19, <<<'EODUMP'
XMLReader {
+localName: "#text"
+nodeType: SIGNIFICANT_WHITESPACE
+depth: 2
+value: """
\n
"""
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(21, <<<'EODUMP'
XMLReader {
+localName: "#text"
+nodeType: SIGNIFICANT_WHITESPACE
+depth: 1
+value: "\n"
+baseURI: "%sxml_reader.xml"
…9
}
EODUMP
),
array(22, <<<'EODUMP'
XMLReader {
+localName: "foo"
+nodeType: END_ELEMENT
+baseURI: "%sxml_reader.xml"
…11
}
EODUMP
),
);
}
}

View File

@@ -1,115 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Cloner;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Caster\ClassStub;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
class DataTest extends TestCase
{
public function testBasicData()
{
$values = array(1 => 123, 4.5, 'abc', null, false);
$data = $this->cloneVar($values);
$clonedValues = array();
$this->assertInstanceOf(Data::class, $data);
$this->assertCount(\count($values), $data);
$this->assertFalse(isset($data->{0}));
$this->assertFalse(isset($data[0]));
foreach ($data as $k => $v) {
$this->assertTrue(isset($data->{$k}));
$this->assertTrue(isset($data[$k]));
$this->assertSame(\gettype($values[$k]), $data->seek($k)->getType());
$this->assertSame($values[$k], $data->seek($k)->getValue());
$this->assertSame($values[$k], $data->{$k});
$this->assertSame($values[$k], $data[$k]);
$this->assertSame((string) $values[$k], (string) $data->seek($k));
$clonedValues[$k] = $v->getValue();
}
$this->assertSame($values, $clonedValues);
}
public function testObject()
{
$data = $this->cloneVar(new \Exception('foo'));
$this->assertSame('Exception', $data->getType());
$this->assertSame('foo', $data->message);
$this->assertSame('foo', $data->{Caster::PREFIX_PROTECTED.'message'});
$this->assertSame('foo', $data['message']);
$this->assertSame('foo', $data[Caster::PREFIX_PROTECTED.'message']);
$this->assertStringMatchesFormat('Exception (count=%d)', (string) $data);
}
public function testArray()
{
$values = array(array(), array(123));
$data = $this->cloneVar($values);
$this->assertSame($values, $data->getValue(true));
$children = $data->getValue();
$this->assertInternalType('array', $children);
$this->assertInstanceOf(Data::class, $children[0]);
$this->assertInstanceOf(Data::class, $children[1]);
$this->assertEquals($children[0], $data[0]);
$this->assertEquals($children[1], $data[1]);
$this->assertSame($values[0], $children[0]->getValue(true));
$this->assertSame($values[1], $children[1]->getValue(true));
}
public function testStub()
{
$data = $this->cloneVar(array(new ClassStub('stdClass')));
$data = $data[0];
$this->assertSame('string', $data->getType());
$this->assertSame('stdClass', $data->getValue());
$this->assertSame('stdClass', (string) $data);
}
public function testHardRefs()
{
$values = array(array());
$values[1] = &$values[0];
$values[2][0] = &$values[2];
$data = $this->cloneVar($values);
$this->assertSame(array(), $data[0]->getValue());
$this->assertSame(array(), $data[1]->getValue());
$this->assertEquals(array($data[2]->getValue()), $data[2]->getValue(true));
$this->assertSame('array (count=3)', (string) $data);
}
private function cloneVar($value)
{
$cloner = new VarCloner();
return $cloner->cloneVar($value);
}
}

View File

@@ -1,437 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Cloner;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\VarCloner;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class VarClonerTest extends TestCase
{
public function testMaxIntBoundary()
{
$data = array(PHP_INT_MAX => 123);
$cloner = new VarCloner();
$clone = $cloner->cloneVar($data);
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
(
[0] => Array
(
[0] => Array
(
[1] => 1
)
)
[1] => Array
(
[%s] => 123
)
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
)
EOTXT;
$this->assertSame(sprintf($expected, PHP_INT_MAX), print_r($clone, true));
}
public function testClone()
{
$json = json_decode('{"1":{"var":"val"},"2":{"var":"val"}}');
$cloner = new VarCloner();
$clone = $cloner->cloneVar($json);
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
(
[0] => Array
(
[0] => Symfony\Component\VarDumper\Cloner\Stub Object
(
[type] => 4
[class] => stdClass
[value] =>
[cut] => 0
[handle] => %i
[refCount] => 0
[position] => 1
[attr] => Array
(
)
)
)
[1] => Array
(
[\000+\0001] => Symfony\Component\VarDumper\Cloner\Stub Object
(
[type] => 4
[class] => stdClass
[value] =>
[cut] => 0
[handle] => %i
[refCount] => 0
[position] => 2
[attr] => Array
(
)
)
[\000+\0002] => Symfony\Component\VarDumper\Cloner\Stub Object
(
[type] => 4
[class] => stdClass
[value] =>
[cut] => 0
[handle] => %i
[refCount] => 0
[position] => 3
[attr] => Array
(
)
)
)
[2] => Array
(
[\000+\000var] => val
)
[3] => Array
(
[\000+\000var] => val
)
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
)
EOTXT;
$this->assertStringMatchesFormat($expected, print_r($clone, true));
}
public function testLimits()
{
// Level 0:
$data = array(
// Level 1:
array(
// Level 2:
array(
// Level 3:
'Level 3 Item 0',
'Level 3 Item 1',
'Level 3 Item 2',
'Level 3 Item 3',
),
array(
'Level 3 Item 4',
'Level 3 Item 5',
'Level 3 Item 6',
),
array(
'Level 3 Item 7',
),
),
array(
array(
'Level 3 Item 8',
),
'Level 2 Item 0',
),
array(
'Level 2 Item 1',
),
'Level 1 Item 0',
array(
// Test setMaxString:
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'SHORT',
),
);
$cloner = new VarCloner();
$cloner->setMinDepth(2);
$cloner->setMaxItems(5);
$cloner->setMaxString(20);
$clone = $cloner->cloneVar($data);
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
(
[0] => Array
(
[0] => Array
(
[2] => 1
)
)
[1] => Array
(
[0] => Array
(
[2] => 2
)
[1] => Array
(
[2] => 3
)
[2] => Array
(
[2] => 4
)
[3] => Level 1 Item 0
[4] => Array
(
[2] => 5
)
)
[2] => Array
(
[0] => Array
(
[2] => 6
)
[1] => Array
(
[0] => 2
[2] => 7
)
[2] => Array
(
[0] => 1
[2] => 0
)
)
[3] => Array
(
[0] => Array
(
[0] => 1
[2] => 0
)
[1] => Level 2 Item 0
)
[4] => Array
(
[0] => Level 2 Item 1
)
[5] => Array
(
[0] => Symfony\Component\VarDumper\Cloner\Stub Object
(
[type] => 2
[class] => 2
[value] => ABCDEFGHIJKLMNOPQRST
[cut] => 6
[handle] => 0
[refCount] => 0
[position] => 0
[attr] => Array
(
)
)
[1] => SHORT
)
[6] => Array
(
[0] => Level 3 Item 0
[1] => Level 3 Item 1
[2] => Level 3 Item 2
[3] => Level 3 Item 3
)
[7] => Array
(
[0] => Level 3 Item 4
)
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
)
EOTXT;
$this->assertStringMatchesFormat($expected, print_r($clone, true));
}
public function testJsonCast()
{
if (2 == ini_get('xdebug.overload_var_dump')) {
$this->markTestSkipped('xdebug is active');
}
$data = (array) json_decode('{"1":{}}');
$cloner = new VarCloner();
$clone = $cloner->cloneVar($data);
$expected = <<<'EOTXT'
object(Symfony\Component\VarDumper\Cloner\Data)#%i (6) {
["data":"Symfony\Component\VarDumper\Cloner\Data":private]=>
array(2) {
[0]=>
array(1) {
[0]=>
array(1) {
[1]=>
int(1)
}
}
[1]=>
array(1) {
["1"]=>
object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) {
["type"]=>
int(4)
["class"]=>
string(8) "stdClass"
["value"]=>
NULL
["cut"]=>
int(0)
["handle"]=>
int(%i)
["refCount"]=>
int(0)
["position"]=>
int(0)
["attr"]=>
array(0) {
}
}
}
}
["position":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(0)
["key":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(0)
["maxDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(20)
["maxItemsPerDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(-1)
["useRefHandles":"Symfony\Component\VarDumper\Cloner\Data":private]=>
int(-1)
}
EOTXT;
ob_start();
var_dump($clone);
$this->assertStringMatchesFormat(\PHP_VERSION_ID >= 70200 ? str_replace('"1"', '1', $expected) : $expected, ob_get_clean());
}
public function testCaster()
{
$cloner = new VarCloner(array(
'*' => function ($obj, $array) {
return array('foo' => 123);
},
__CLASS__ => function ($obj, $array) {
++$array['foo'];
return $array;
},
));
$clone = $cloner->cloneVar($this);
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
(
[0] => Array
(
[0] => Symfony\Component\VarDumper\Cloner\Stub Object
(
[type] => 4
[class] => %s
[value] =>
[cut] => 0
[handle] => %i
[refCount] => 0
[position] => 1
[attr] => Array
(
)
)
)
[1] => Array
(
[foo] => 124
)
)
[position:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[key:Symfony\Component\VarDumper\Cloner\Data:private] => 0
[maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20
[maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1
[useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1
)
EOTXT;
$this->assertStringMatchesFormat($expected, print_r($clone, true));
}
}

View File

@@ -1,541 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Dumper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
use Twig\Environment;
use Twig\Loader\FilesystemLoader;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class CliDumperTest extends TestCase
{
use VarDumperTestTrait;
public function testGet()
{
require __DIR__.'/../Fixtures/dumb-var.php';
$dumper = new CliDumper('php://output');
$dumper->setColors(false);
$cloner = new VarCloner();
$cloner->addCasters(array(
':stream' => function ($res, $a) {
unset($a['uri'], $a['wrapper_data']);
return $a;
},
));
$data = $cloner->cloneVar($var);
ob_start();
$dumper->dump($data);
$out = ob_get_clean();
$out = preg_replace('/[ \t]+$/m', '', $out);
$intMax = PHP_INT_MAX;
$res = (int) $var['res'];
$this->assertStringMatchesFormat(
<<<EOTXT
array:24 [
"number" => 1
0 => &1 null
"const" => 1.1
1 => true
2 => false
3 => NAN
4 => INF
5 => -INF
6 => {$intMax}
"str" => "déjà\\n"
7 => b"""
é\\x00test\\t\\n
ing
"""
"[]" => []
"res" => stream resource {@{$res}
%A wrapper_type: "plainfile"
stream_type: "STDIO"
mode: "r"
unread_bytes: 0
seekable: true
%A options: []
}
"obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d
+foo: "foo"
+"bar": "bar"
}
"closure" => Closure(\$a, PDO &\$b = null) {#%d
class: "Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest"
this: Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest {#%d …}
parameters: {
\$a: {}
&\$b: {
typeHint: "PDO"
default: null
}
}
file: "%s%eTests%eFixtures%edumb-var.php"
line: "{$var['line']} to {$var['line']}"
}
"line" => {$var['line']}
"nobj" => array:1 [
0 => &3 {#%d}
]
"recurs" => &4 array:1 [
0 => &4 array:1 [&4]
]
8 => &1 null
"sobj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d}
"snobj" => &3 {#%d}
"snobj2" => {#%d}
"file" => "{$var['file']}"
b"bin-key-é" => ""
]
EOTXT
,
$out
);
}
/**
* @dataProvider provideDumpWithCommaFlagTests
*/
public function testDumpWithCommaFlag($expected, $flags)
{
$dumper = new CliDumper(null, null, $flags);
$dumper->setColors(false);
$cloner = new VarCloner();
$var = array(
'array' => array('a', 'b'),
'string' => 'hello',
'multiline string' => "this\nis\na\multiline\nstring",
);
$dump = $dumper->dump($cloner->cloneVar($var), true);
$this->assertSame($expected, $dump);
}
public function testDumpWithCommaFlagsAndExceptionCodeExcerpt()
{
$dumper = new CliDumper(null, null, CliDumper::DUMP_TRAILING_COMMA);
$dumper->setColors(false);
$cloner = new VarCloner();
$ex = new \RuntimeException('foo');
$dump = $dumper->dump($cloner->cloneVar($ex)->withRefHandles(false), true);
$this->assertStringMatchesFormat(<<<'EOTXT'
RuntimeException {
#message: "foo"
#code: 0
#file: "%ACliDumperTest.php"
#line: %d
trace: {
%ACliDumperTest.php:%d {
$ex = new \RuntimeException('foo');
}
%A
}
}
EOTXT
, $dump);
}
public function provideDumpWithCommaFlagTests()
{
$expected = <<<'EOTXT'
array:3 [
"array" => array:2 [
0 => "a",
1 => "b"
],
"string" => "hello",
"multiline string" => """
this\n
is\n
a\multiline\n
string
"""
]
EOTXT;
yield array($expected, CliDumper::DUMP_COMMA_SEPARATOR);
$expected = <<<'EOTXT'
array:3 [
"array" => array:2 [
0 => "a",
1 => "b",
],
"string" => "hello",
"multiline string" => """
this\n
is\n
a\multiline\n
string
""",
]
EOTXT;
yield array($expected, CliDumper::DUMP_TRAILING_COMMA);
}
/**
* @requires extension xml
*/
public function testXmlResource()
{
$var = xml_parser_create();
$this->assertDumpMatchesFormat(
<<<'EOTXT'
xml resource {
current_byte_index: %i
current_column_number: %i
current_line_number: 1
error_code: XML_ERROR_NONE
}
EOTXT
,
$var
);
}
public function testJsonCast()
{
$var = (array) json_decode('{"0":{},"1":null}');
foreach ($var as &$v) {
}
$var[] = &$v;
$var[''] = 2;
if (\PHP_VERSION_ID >= 70200) {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
array:4 [
0 => {}
1 => &1 null
2 => &1 null
"" => 2
]
EOTXT
,
$var
);
} else {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
array:4 [
"0" => {}
"1" => &1 null
0 => &1 null
"" => 2
]
EOTXT
,
$var
);
}
}
public function testObjectCast()
{
$var = (object) array(1 => 1);
$var->{1} = 2;
if (\PHP_VERSION_ID >= 70200) {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
{
+"1": 2
}
EOTXT
,
$var
);
} else {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
{
+1: 1
+"1": 2
}
EOTXT
,
$var
);
}
}
public function testClosedResource()
{
$var = fopen(__FILE__, 'r');
fclose($var);
$dumper = new CliDumper('php://output');
$dumper->setColors(false);
$cloner = new VarCloner();
$data = $cloner->cloneVar($var);
ob_start();
$dumper->dump($data);
$out = ob_get_clean();
$res = (int) $var;
$this->assertStringMatchesFormat(
<<<EOTXT
Closed resource @{$res}
EOTXT
,
$out
);
}
public function testFlags()
{
putenv('DUMP_LIGHT_ARRAY=1');
putenv('DUMP_STRING_LENGTH=1');
$var = array(
range(1, 3),
array('foo', 2 => 'bar'),
);
$this->assertDumpEquals(
<<<EOTXT
[
[
1
2
3
]
[
0 => (3) "foo"
2 => (3) "bar"
]
]
EOTXT
,
$var
);
putenv('DUMP_LIGHT_ARRAY=');
putenv('DUMP_STRING_LENGTH=');
}
/**
* @requires function Twig\Template::getSourceContext
*/
public function testThrowingCaster()
{
$out = fopen('php://memory', 'r+b');
require_once __DIR__.'/../Fixtures/Twig.php';
$twig = new \__TwigTemplate_VarDumperFixture_u75a09(new Environment(new FilesystemLoader()));
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$cloner->addCasters(array(
':stream' => function ($res, $a) {
unset($a['wrapper_data']);
return $a;
},
));
$cloner->addCasters(array(
':stream' => eval('return function () use ($twig) {
try {
$twig->render(array());
} catch (\Twig\Error\RuntimeError $e) {
throw $e->getPrevious();
}
};'),
));
$ref = (int) $out;
$data = $cloner->cloneVar($out);
$dumper->dump($data, $out);
$out = stream_get_contents($out, -1, 0);
$this->assertStringMatchesFormat(
<<<EOTXT
stream resource {@{$ref}
⚠: Symfony\Component\VarDumper\Exception\ThrowingCasterException {#%d
#message: "Unexpected Exception thrown from a caster: Foobar"
trace: {
%sTwig.php:2 {
foo bar
twig source
}
%s%eTemplate.php:%d { …}
%s%eTemplate.php:%d { …}
%s%eTemplate.php:%d { …}
%s%eTests%eDumper%eCliDumperTest.php:%d { …}
%A }
}
%Awrapper_type: "PHP"
stream_type: "MEMORY"
mode: "%s+b"
unread_bytes: 0
seekable: true
uri: "php://memory"
%Aoptions: []
}
EOTXT
,
$out
);
}
public function testRefsInProperties()
{
$var = (object) array('foo' => 'foo');
$var->bar = &$var->foo;
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$data = $cloner->cloneVar($var);
$out = $dumper->dump($data, true);
$this->assertStringMatchesFormat(
<<<EOTXT
{#%d
+"foo": &1 "foo"
+"bar": &1 "foo"
}
EOTXT
,
$out
);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testSpecialVars56()
{
$var = $this->getSpecialVars();
$this->assertDumpEquals(
<<<'EOTXT'
array:3 [
0 => array:1 [
0 => &1 array:1 [
0 => &1 array:1 [&1]
]
]
1 => array:1 [
"GLOBALS" => &2 array:1 [
"GLOBALS" => &2 array:1 [&2]
]
]
2 => &2 array:1 [&2]
]
EOTXT
,
$var
);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testGlobals()
{
$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();
$data = $cloner->cloneVar($var);
$dumper->dump($data);
$this->assertSame(
<<<'EOTXT'
array:2 [
1 => array:1 [
"GLOBALS" => &1 array:1 [
"GLOBALS" => &1 array:1 [&1]
]
]
2 => &1 array:1 [&1]
]
EOTXT
,
$out
);
}
public function testIncompleteClass()
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', null);
$var = unserialize('O:8:"Foo\Buzz":0:{}');
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
$this->assertDumpMatchesFormat(
<<<EOTXT
__PHP_Incomplete_Class(Foo\Buzz) {}
EOTXT
,
$var
);
}
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);
}
}

View File

@@ -1,57 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Dumper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\VarDumper;
class FunctionsTest extends TestCase
{
public function testDumpReturnsFirstArg()
{
$this->setupVarDumper();
$var1 = 'a';
ob_start();
$return = dump($var1);
$out = ob_get_clean();
$this->assertEquals($var1, $return);
}
public function testDumpReturnsAllArgsInArray()
{
$this->setupVarDumper();
$var1 = 'a';
$var2 = 'b';
$var3 = 'c';
ob_start();
$return = dump($var1, $var2, $var3);
$out = ob_get_clean();
$this->assertEquals(array($var1, $var2, $var3), $return);
}
protected function setupVarDumper()
{
$cloner = new VarCloner();
$dumper = new CliDumper('php://output');
VarDumper::setHandler(function ($var) use ($cloner, $dumper) {
$dumper->dump($cloner->cloneVar($var));
});
}
}

View File

@@ -1,170 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Dumper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class HtmlDumperTest extends TestCase
{
public function testGet()
{
if (ini_get('xdebug.file_link_format') || get_cfg_var('xdebug.file_link_format')) {
$this->markTestSkipped('A custom file_link_format is defined.');
}
require __DIR__.'/../Fixtures/dumb-var.php';
$dumper = new HtmlDumper('php://output');
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$cloner = new VarCloner();
$cloner->addCasters(array(
':stream' => function ($res, $a) {
unset($a['uri'], $a['wrapper_data']);
return $a;
},
));
$data = $cloner->cloneVar($var);
ob_start();
$dumper->dump($data);
$out = ob_get_clean();
$out = preg_replace('/[ \t]+$/m', '', $out);
$var['file'] = htmlspecialchars($var['file'], ENT_QUOTES, 'UTF-8');
$intMax = PHP_INT_MAX;
preg_match('/sf-dump-\d+/', $out, $dumpId);
$dumpId = $dumpId[0];
$res = (int) $var['res'];
$this->assertStringMatchesFormat(
<<<EOTXT
<foo></foo><bar><span class=sf-dump-note>array:24</span> [<samp>
"<span class=sf-dump-key>number</span>" => <span class=sf-dump-num>1</span>
<span class=sf-dump-key>0</span> => <a class=sf-dump-ref href=#{$dumpId}-ref01 title="2 occurrences">&amp;1</a> <span class=sf-dump-const>null</span>
"<span class=sf-dump-key>const</span>" => <span class=sf-dump-num>1.1</span>
<span class=sf-dump-key>1</span> => <span class=sf-dump-const>true</span>
<span class=sf-dump-key>2</span> => <span class=sf-dump-const>false</span>
<span class=sf-dump-key>3</span> => <span class=sf-dump-num>NAN</span>
<span class=sf-dump-key>4</span> => <span class=sf-dump-num>INF</span>
<span class=sf-dump-key>5</span> => <span class=sf-dump-num>-INF</span>
<span class=sf-dump-key>6</span> => <span class=sf-dump-num>{$intMax}</span>
"<span class=sf-dump-key>str</span>" => "<span class=sf-dump-str title="5 characters">d&%s;j&%s;<span class="sf-dump-default sf-dump-ns">\\n</span></span>"
<span class=sf-dump-key>7</span> => b"""
<span class=sf-dump-str title="11 binary or non-UTF-8 characters">&eacute;<span class="sf-dump-default">\\x00</span>test<span class="sf-dump-default">\\t</span><span class="sf-dump-default sf-dump-ns">\\n</span></span>
<span class=sf-dump-str title="11 binary or non-UTF-8 characters">ing</span>
"""
"<span class=sf-dump-key>[]</span>" => []
"<span class=sf-dump-key>res</span>" => <span class=sf-dump-note>stream resource</span> <a class=sf-dump-ref>@{$res}</a><samp>
%A <span class=sf-dump-meta>wrapper_type</span>: "<span class=sf-dump-str title="9 characters">plainfile</span>"
<span class=sf-dump-meta>stream_type</span>: "<span class=sf-dump-str title="5 characters">STDIO</span>"
<span class=sf-dump-meta>mode</span>: "<span class=sf-dump-str>r</span>"
<span class=sf-dump-meta>unread_bytes</span>: <span class=sf-dump-num>0</span>
<span class=sf-dump-meta>seekable</span>: <span class=sf-dump-const>true</span>
%A <span class=sf-dump-meta>options</span>: []
</samp>}
"<span class=sf-dump-key>obj</span>" => <abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr> {<a class=sf-dump-ref href=#{$dumpId}-ref2%d title="2 occurrences">#%d</a><samp id={$dumpId}-ref2%d>
+<span class=sf-dump-public title="Public property">foo</span>: "<span class=sf-dump-str title="3 characters">foo</span>"
+"<span class=sf-dump-public title="Runtime added dynamic property">bar</span>": "<span class=sf-dump-str title="3 characters">bar</span>"
</samp>}
"<span class=sf-dump-key>closure</span>" => <span class=sf-dump-note>Closure(\$a, PDO &amp;\$b = null)</span> {<a class=sf-dump-ref>#%d</a><samp>
<span class=sf-dump-meta>class</span>: "<span class=sf-dump-str title="Symfony\Component\VarDumper\Tests\Dumper\HtmlDumperTest
55 characters"><span class="sf-dump-ellipsis sf-dump-ellipsis-class">Symfony\Component\VarDumper\Tests\Dumper</span><span class=sf-dump-ellipsis>\</span>HtmlDumperTest</span>"
<span class=sf-dump-meta>this</span>: <abbr title="Symfony\Component\VarDumper\Tests\Dumper\HtmlDumperTest" class=sf-dump-note>HtmlDumperTest</abbr> {<a class=sf-dump-ref>#%d</a> &%s;}
<span class=sf-dump-meta>parameters</span>: {<samp>
<span class=sf-dump-meta>\$a</span>: {}
<span class=sf-dump-meta>&amp;\$b</span>: {<samp>
<span class=sf-dump-meta>typeHint</span>: "<span class=sf-dump-str title="3 characters">PDO</span>"
<span class=sf-dump-meta>default</span>: <span class=sf-dump-const>null</span>
</samp>}
</samp>}
<span class=sf-dump-meta>file</span>: "<span class=sf-dump-str title="{$var['file']}
%d characters"><span class="sf-dump-ellipsis sf-dump-ellipsis-path">%s%eVarDumper</span><span class=sf-dump-ellipsis>%e</span>Tests%eFixtures%edumb-var.php</span>"
<span class=sf-dump-meta>line</span>: "<span class=sf-dump-str title="%d characters">{$var['line']} to {$var['line']}</span>"
</samp>}
"<span class=sf-dump-key>line</span>" => <span class=sf-dump-num>{$var['line']}</span>
"<span class=sf-dump-key>nobj</span>" => <span class=sf-dump-note>array:1</span> [<samp>
<span class=sf-dump-index>0</span> => <a class=sf-dump-ref href=#{$dumpId}-ref03 title="2 occurrences">&amp;3</a> {<a class=sf-dump-ref href=#{$dumpId}-ref2%d title="3 occurrences">#%d</a>}
</samp>]
"<span class=sf-dump-key>recurs</span>" => <a class=sf-dump-ref href=#{$dumpId}-ref04 title="2 occurrences">&amp;4</a> <span class=sf-dump-note>array:1</span> [<samp id={$dumpId}-ref04>
<span class=sf-dump-index>0</span> => <a class=sf-dump-ref href=#{$dumpId}-ref04 title="2 occurrences">&amp;4</a> <span class=sf-dump-note>array:1</span> [<a class=sf-dump-ref href=#{$dumpId}-ref04 title="2 occurrences">&amp;4</a>]
</samp>]
<span class=sf-dump-key>8</span> => <a class=sf-dump-ref href=#{$dumpId}-ref01 title="2 occurrences">&amp;1</a> <span class=sf-dump-const>null</span>
"<span class=sf-dump-key>sobj</span>" => <abbr title="Symfony\Component\VarDumper\Tests\Fixture\DumbFoo" class=sf-dump-note>DumbFoo</abbr> {<a class=sf-dump-ref href=#{$dumpId}-ref2%d title="2 occurrences">#%d</a>}
"<span class=sf-dump-key>snobj</span>" => <a class=sf-dump-ref href=#{$dumpId}-ref03 title="2 occurrences">&amp;3</a> {<a class=sf-dump-ref href=#{$dumpId}-ref2%d title="3 occurrences">#%d</a>}
"<span class=sf-dump-key>snobj2</span>" => {<a class=sf-dump-ref href=#{$dumpId}-ref2%d title="3 occurrences">#%d</a>}
"<span class=sf-dump-key>file</span>" => "<span class=sf-dump-str title="%d characters">{$var['file']}</span>"
b"<span class=sf-dump-key>bin-key-&%s;</span>" => ""
</samp>]
</bar>
EOTXT
,
$out
);
}
public function testCharset()
{
$var = mb_convert_encoding('Словарь', 'CP1251', 'UTF-8');
$dumper = new HtmlDumper('php://output', 'CP1251');
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$cloner = new VarCloner();
$data = $cloner->cloneVar($var);
$out = $dumper->dump($data, true);
$this->assertStringMatchesFormat(
<<<'EOTXT'
<foo></foo><bar>b"<span class=sf-dump-str title="7 binary or non-UTF-8 characters">&#1057;&#1083;&#1086;&#1074;&#1072;&#1088;&#1100;</span>"
</bar>
EOTXT
,
$out
);
}
public function testAppend()
{
$out = fopen('php://memory', 'r+b');
$dumper = new HtmlDumper();
$dumper->setDumpHeader('<foo></foo>');
$dumper->setDumpBoundaries('<bar>', '</bar>');
$cloner = new VarCloner();
$dumper->dump($cloner->cloneVar(123), $out);
$dumper->dump($cloner->cloneVar(456), $out);
$out = stream_get_contents($out, -1, 0);
$this->assertSame(<<<'EOTXT'
<foo></foo><bar><span class=sf-dump-num>123</span>
</bar>
<bar><span class=sf-dump-num>456</span>
</bar>
EOTXT
,
$out
);
}
}

View File

@@ -1,95 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Dumper;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\PhpProcess;
use Symfony\Component\Process\Process;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
use Symfony\Component\VarDumper\Dumper\ServerDumper;
class ServerDumperTest extends TestCase
{
private const VAR_DUMPER_SERVER = 'tcp://127.0.0.1:9913';
public function testDumpForwardsToWrappedDumperWhenServerIsUnavailable()
{
$wrappedDumper = $this->getMockBuilder(DataDumperInterface::class)->getMock();
$dumper = new ServerDumper(self::VAR_DUMPER_SERVER, $wrappedDumper);
$cloner = new VarCloner();
$data = $cloner->cloneVar('foo');
$wrappedDumper->expects($this->once())->method('dump')->with($data);
$dumper->dump($data);
}
public function testDump()
{
$wrappedDumper = $this->getMockBuilder(DataDumperInterface::class)->getMock();
$wrappedDumper->expects($this->never())->method('dump'); // test wrapped dumper is not used
$cloner = new VarCloner();
$data = $cloner->cloneVar('foo');
$dumper = new ServerDumper(self::VAR_DUMPER_SERVER, $wrappedDumper, array(
'foo_provider' => new class() implements ContextProviderInterface {
public function getContext(): ?array
{
return array('foo');
}
},
));
$dumped = null;
$process = $this->getServerProcess();
$process->start(function ($type, $buffer) use ($process, &$dumped, $dumper, $data) {
if (Process::ERR === $type) {
$process->stop();
$this->fail();
} elseif ("READY\n" === $buffer) {
$dumper->dump($data);
} else {
$dumped .= $buffer;
}
});
$process->wait();
$this->assertTrue($process->isSuccessful());
$this->assertStringMatchesFormat(<<<'DUMP'
(3) "foo"
[
"timestamp" => %d.%d
"foo_provider" => [
(3) "foo"
]
]
%d
DUMP
, $dumped);
}
private function getServerProcess(): Process
{
$process = new PhpProcess(file_get_contents(__DIR__.'/../Fixtures/dump_server.php'), null, array(
'COMPONENT_ROOT' => __DIR__.'/../../',
'VAR_DUMPER_SERVER' => self::VAR_DUMPER_SERVER,
));
$process->inheritEnvironmentVariables(true);
return $process->setTimeout(9);
}
}

View File

@@ -1,11 +0,0 @@
<?php
namespace Symfony\Component\VarDumper\Tests\Fixtures;
interface FooInterface
{
/**
* Hello.
*/
public function foo(?\stdClass $a, \stdClass $b = null);
}

View File

@@ -1,21 +0,0 @@
<?php
namespace Symfony\Component\VarDumper\Tests\Fixtures;
class GeneratorDemo
{
public static function foo()
{
yield 1;
}
public function baz()
{
yield from bar();
}
}
function bar()
{
yield from GeneratorDemo::foo();
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Symfony\Component\VarDumper\Tests\Fixtures;
class NotLoadableClass extends NotLoadableClass
{
}

View File

@@ -1,38 +0,0 @@
<?php
/* foo.twig */
class __TwigTemplate_VarDumperFixture_u75a09 extends Twig\Template
{
private $path;
public function __construct(Twig\Environment $env = null, $path = null)
{
if (null !== $env) {
parent::__construct($env);
}
$this->parent = false;
$this->blocks = array();
$this->path = $path;
}
protected function doDisplay(array $context, array $blocks = array())
{
// line 2
throw new \Exception('Foobar');
}
public function getTemplateName()
{
return 'foo.twig';
}
public function getDebugInfo()
{
return array(20 => 1, 21 => 2);
}
public function getSourceContext()
{
return new Twig\Source(" foo bar\n twig source\n\n", 'foo.twig', $this->path ?: __FILE__);
}
}

View File

@@ -1,40 +0,0 @@
<?php
namespace Symfony\Component\VarDumper\Tests\Fixture;
if (!class_exists('Symfony\Component\VarDumper\Tests\Fixture\DumbFoo')) {
class DumbFoo
{
public $foo = 'foo';
}
}
$foo = new DumbFoo();
$foo->bar = 'bar';
$g = fopen(__FILE__, 'r');
$var = array(
'number' => 1, null,
'const' => 1.1, true, false, NAN, INF, -INF, PHP_INT_MAX,
'str' => "déjà\n", "\xE9\x00test\t\ning",
'[]' => array(),
'res' => $g,
'obj' => $foo,
'closure' => function ($a, \PDO &$b = null) {},
'line' => __LINE__ - 1,
'nobj' => array((object) array()),
);
$r = array();
$r[] = &$r;
$var['recurs'] = &$r;
$var[] = &$var[0];
$var['sobj'] = $var['obj'];
$var['snobj'] = &$var['nobj'][0];
$var['snobj2'] = $var['nobj'][0];
$var['file'] = __FILE__;
$var["bin-key-\xE9"] = '';
unset($g, $r);

View File

@@ -1,38 +0,0 @@
<?php
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Server\DumpServer;
use Symfony\Component\VarDumper\VarDumper;
$componentRoot = $_SERVER['COMPONENT_ROOT'];
if (!is_file($file = $componentRoot.'/vendor/autoload.php')) {
$file = $componentRoot.'/../../../../vendor/autoload.php';
}
require $file;
$cloner = new VarCloner();
$cloner->setMaxItems(-1);
$dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_STRING_LENGTH);
$dumper->setColors(false);
VarDumper::setHandler(function ($var) use ($cloner, $dumper) {
$data = $cloner->cloneVar($var)->withRefHandles(false);
$dumper->dump($data);
});
$server = new DumpServer(getenv('VAR_DUMPER_SERVER'));
$server->start();
echo "READY\n";
$server->listen(function (Data $data, array $context, $clientId) {
dump((string) $data, $context, $clientId);
exit(0);
});

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar></bar>
<bar />
<bar>With text</bar>
<bar foo="bar" baz="fubar"></bar>
<bar xmlns:baz="http://symfony.com">
<baz:baz></baz:baz>
</bar>
</foo>

View File

@@ -1,88 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Server;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\PhpProcess;
use Symfony\Component\Process\Process;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface;
use Symfony\Component\VarDumper\Server\Connection;
class ConnectionTest extends TestCase
{
private const VAR_DUMPER_SERVER = 'tcp://127.0.0.1:9913';
public function testDump()
{
$cloner = new VarCloner();
$data = $cloner->cloneVar('foo');
$connection = new Connection(self::VAR_DUMPER_SERVER, array(
'foo_provider' => new class() implements ContextProviderInterface {
public function getContext(): ?array
{
return array('foo');
}
},
));
$dumped = null;
$process = $this->getServerProcess();
$process->start(function ($type, $buffer) use ($process, &$dumped, $connection, $data) {
if (Process::ERR === $type) {
$process->stop();
$this->fail();
} elseif ("READY\n" === $buffer) {
$connection->write($data);
} else {
$dumped .= $buffer;
}
});
$process->wait();
$this->assertTrue($process->isSuccessful());
$this->assertStringMatchesFormat(<<<'DUMP'
(3) "foo"
[
"timestamp" => %d.%d
"foo_provider" => [
(3) "foo"
]
]
%d
DUMP
, $dumped);
}
public function testNoServer()
{
$cloner = new VarCloner();
$data = $cloner->cloneVar('foo');
$connection = new Connection(self::VAR_DUMPER_SERVER);
$start = microtime(true);
$this->assertFalse($connection->write($data));
$this->assertLessThan(1, microtime(true) - $start);
}
private function getServerProcess(): Process
{
$process = new PhpProcess(file_get_contents(__DIR__.'/../Fixtures/dump_server.php'), null, array(
'COMPONENT_ROOT' => __DIR__.'/../../',
'VAR_DUMPER_SERVER' => self::VAR_DUMPER_SERVER,
));
$process->inheritEnvironmentVariables(true);
return $process->setTimeout(9);
}
}

View File

@@ -1,46 +0,0 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\VarDumper\Tests\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
class VarDumperTestTraitTest extends TestCase
{
use VarDumperTestTrait;
public function testItComparesLargeData()
{
$howMany = 700;
$data = array_fill_keys(range(0, $howMany), array('a', 'b', 'c', 'd'));
$expected = sprintf("array:%d [\n", $howMany + 1);
for ($i = 0; $i <= $howMany; ++$i) {
$expected .= <<<EODUMP
$i => array:4 [
0 => "a"
1 => "b"
2 => "c"
3 => "d"
]\n
EODUMP;
}
$expected .= "]\n";
$this->assertDumpEquals($expected, $data);
}
public function testAllowsNonScalarExpectation()
{
$this->assertDumpEquals(new \ArrayObject(array('bim' => 'bam')), new \ArrayObject(array('bim' => 'bam')));
}
}

View File

@@ -11,8 +11,11 @@
namespace Symfony\Component\VarDumper;
use Symfony\Component\VarDumper\Caster\ReflectionCaster;
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider;
use Symfony\Component\VarDumper\Dumper\ContextualizedDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
// Load the global dump() function
@@ -29,24 +32,33 @@ class VarDumper
{
if (null === self::$handler) {
$cloner = new VarCloner();
$cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO);
if (isset($_SERVER['VAR_DUMPER_FORMAT'])) {
$dumper = 'html' === $_SERVER['VAR_DUMPER_FORMAT'] ? new HtmlDumper() : new CliDumper();
} else {
$dumper = \in_array(\PHP_SAPI, array('cli', 'phpdbg')) ? new CliDumper() : new HtmlDumper();
$dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg']) ? new CliDumper() : new HtmlDumper();
}
$dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]);
self::$handler = function ($var) use ($cloner, $dumper) {
$dumper->dump($cloner->cloneVar($var));
};
}
return \call_user_func(self::$handler, $var);
return (self::$handler)($var);
}
public static function setHandler(callable $callable = null)
{
$prevHandler = self::$handler;
// Prevent replacing the handler with expected format as soon as the env var was set:
if (isset($_SERVER['VAR_DUMPER_FORMAT'])) {
return $prevHandler;
}
self::$handler = $callable;
return $prevHandler;

View File

@@ -1,7 +1,7 @@
{
"name": "symfony/var-dumper",
"type": "library",
"description": "Symfony mechanism for exploring and dumping PHP variables",
"description": "Provides mechanisms for walking through any arbitrary PHP variable",
"keywords": ["dump", "debug"],
"homepage": "https://symfony.com",
"license": "MIT",
@@ -16,14 +16,16 @@
}
],
"require": {
"php": "^7.1.3",
"php": ">=7.1.3",
"symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php72": "~1.5"
"symfony/polyfill-php72": "~1.5",
"symfony/polyfill-php80": "^1.16"
},
"require-dev": {
"ext-iconv": "*",
"symfony/process": "~3.4|~4.0",
"twig/twig": "~1.34|~2.4"
"symfony/console": "^3.4|^4.0|^5.0",
"symfony/process": "^4.4|^5.0",
"twig/twig": "^1.43|^2.13|^3.0.4"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
@@ -44,10 +46,5 @@
"bin": [
"Resources/bin/var-dump-server"
],
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
}
}
"minimum-stability": "dev"
}

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
<env name="DUMP_LIGHT_ARRAY" value="" />
<env name="DUMP_STRING_LENGTH" value="" />
</php>
<testsuites>
<testsuite name="Symfony VarDumper Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Resources</directory>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>