This commit is contained in:
Laurent Destailleur 2021-10-19 21:04:19 +02:00
commit c038c1881a
51 changed files with 5322 additions and 3515 deletions

View File

@ -35,7 +35,7 @@
"nnnick/chartjs" : "^2.9",
"stripe/stripe-php" : "6.43.1",
"maximebf/debugbar" : "1.15.1",
"symfony/var-dumper" : "3"
"symfony/var-dumper" : "3.2"
},
"require-dev" : {
"php-parallel-lint/php-parallel-lint" : "^0",

4
composer.lock generated
View File

@ -591,7 +591,7 @@
},
{
"name": "symfony/var-dumper",
"version": "v3.0.0",
"version": "v3.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
@ -616,7 +616,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {

View File

@ -20,145 +20,191 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
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 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 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 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',
);
public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
// BC layer in the ampq lib
if (method_exists($c, 'getReadTimeout')) {
$timeout = $c->getReadTimeout();
} else {
$timeout = $c->getTimeout();
}
$a += array(
$prefix.'is_connected' => $c->isConnected(),
);
$a += array(
$prefix.'isConnected' => $c->isConnected(),
$prefix.'login' => $c->getLogin(),
$prefix.'password' => $c->getPassword(),
$prefix.'host' => $c->getHost(),
$prefix.'port' => $c->getPort(),
$prefix.'vhost' => $c->getVhost(),
$prefix.'readTimeout' => $timeout,
);
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPConnection\x00login"])) {
return $a;
}
return $a;
}
// BC layer in the amqp lib
if (method_exists($c, 'getReadTimeout')) {
$timeout = $c->getReadTimeout();
} else {
$timeout = $c->getTimeout();
}
public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$prefix.'is_connected' => $c->isConnected(),
$prefix.'login' => $c->getLogin(),
$prefix.'password' => $c->getPassword(),
$prefix.'host' => $c->getHost(),
$prefix.'vhost' => $c->getVhost(),
$prefix.'port' => $c->getPort(),
$prefix.'read_timeout' => $timeout,
);
$a += array(
$prefix.'isConnected' => $c->isConnected(),
$prefix.'channelId' => $c->getChannelId(),
$prefix.'prefetchSize' => $c->getPrefetchSize(),
$prefix.'prefetchCount' => $c->getPrefetchCount(),
$prefix.'connection' => $c->getConnection(),
);
return $a;
}
return $a;
}
public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$prefix.'is_connected' => $c->isConnected(),
$prefix.'channel_id' => $c->getChannelId(),
);
$a += array(
$prefix.'name' => $c->getName(),
$prefix.'flags' => self::extractFlags($c->getFlags()),
$prefix.'arguments' => $c->getArguments(),
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
);
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPChannel\x00connection"])) {
return $a;
}
return $a;
}
$a += array(
$prefix.'connection' => $c->getConnection(),
$prefix.'prefetch_size' => $c->getPrefetchSize(),
$prefix.'prefetch_count' => $c->getPrefetchCount(),
);
public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a;
}
$a += array(
$prefix.'name' => $c->getName(),
$prefix.'flags' => self::extractFlags($c->getFlags()),
$prefix.'type' => isset(self::$exchangeTypes[$c->getType()]) ? new ConstStub(self::$exchangeTypes[$c->getType()], $c->getType()) : $c->getType(),
$prefix.'arguments' => $c->getArguments(),
$prefix.'channel' => $c->getChannel(),
$prefix.'connection' => $c->getConnection(),
);
public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a;
}
$a += array(
$prefix.'flags' => self::extractFlags($c->getFlags()),
);
public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPQueue\x00name"])) {
return $a;
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$a += array($prefix.'body' => $c->getBody());
}
$a += array(
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'arguments' => $c->getArguments(),
);
$a += array(
$prefix.'routingKey' => $c->getRoutingKey(),
$prefix.'deliveryTag' => $c->getDeliveryTag(),
$prefix.'deliveryMode' => new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()),
$prefix.'exchangeName' => $c->getExchangeName(),
$prefix.'isRedelivery' => $c->isRedelivery(),
$prefix.'contentType' => $c->getContentType(),
$prefix.'contentEncoding' => $c->getContentEncoding(),
$prefix.'type' => $c->getType(),
$prefix.'timestamp' => $c->getTimestamp(),
$prefix.'priority' => $c->getPriority(),
$prefix.'expiration' => $c->getExpiration(),
$prefix.'userId' => $c->getUserId(),
$prefix.'appId' => $c->getAppId(),
$prefix.'messageId' => $c->getMessageId(),
$prefix.'replyTo' => $c->getReplyTo(),
$prefix.'correlationId' => $c->getCorrelationId(),
$prefix.'headers' => $c->getHeaders(),
);
return $a;
}
return $a;
}
public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
private static function extractFlags($flags)
{
$flagsArray = array();
$a += array(
$prefix.'flags' => self::extractFlags($c->getFlags()),
);
foreach (self::$flags as $value => $name) {
if ($flags & $value) {
$flagsArray[] = $name;
}
}
$type = isset(self::$exchangeTypes[$c->getType()]) ? new ConstStub(self::$exchangeTypes[$c->getType()], $c->getType()) : $c->getType();
if (!$flagsArray) {
$flagsArray = array('AMQP_NOPARAM');
}
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPExchange\x00name"])) {
$a["\x00AMQPExchange\x00type"] = $type;
return new ConstStub(implode('|', $flagsArray), $flags);
}
return $a;
}
$a += array(
$prefix.'connection' => $c->getConnection(),
$prefix.'channel' => $c->getChannel(),
$prefix.'name' => $c->getName(),
$prefix.'type' => $type,
$prefix.'arguments' => $c->getArguments(),
);
return $a;
}
public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
$deliveryMode = new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode());
// Recent version of the extension already expose private properties
if (isset($a["\x00AMQPEnvelope\x00body"])) {
$a["\0AMQPEnvelope\0delivery_mode"] = $deliveryMode;
return $a;
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$a += array($prefix.'body' => $c->getBody());
}
$a += array(
$prefix.'delivery_tag' => $c->getDeliveryTag(),
$prefix.'is_redelivery' => $c->isRedelivery(),
$prefix.'exchange_name' => $c->getExchangeName(),
$prefix.'routing_key' => $c->getRoutingKey(),
$prefix.'content_type' => $c->getContentType(),
$prefix.'content_encoding' => $c->getContentEncoding(),
$prefix.'headers' => $c->getHeaders(),
$prefix.'delivery_mode' => $deliveryMode,
$prefix.'priority' => $c->getPriority(),
$prefix.'correlation_id' => $c->getCorrelationId(),
$prefix.'reply_to' => $c->getReplyTo(),
$prefix.'expiration' => $c->getExpiration(),
$prefix.'message_id' => $c->getMessageId(),
$prefix.'timestamp' => $c->getTimeStamp(),
$prefix.'type' => $c->getType(),
$prefix.'user_id' => $c->getUserId(),
$prefix.'app_id' => $c->getAppId(),
);
return $a;
}
private static function extractFlags($flags)
{
$flagsArray = array();
foreach (self::$flags as $value => $name) {
if ($flags & $value) {
$flagsArray[] = $name;
}
}
if (!$flagsArray) {
$flagsArray = array('AMQP_NOPARAM');
}
return new ConstStub(implode('|', $flagsArray), $flags);
}
}

View File

@ -0,0 +1,80 @@
<?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;
/**
* Represents a list of function arguments.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ArgsStub extends EnumStub
{
private static $parameters = array();
public function __construct(array $args, $function, $class)
{
list($variadic, $params) = self::getParameters($function, $class);
$values = array();
foreach ($args as $k => $v) {
$values[$k] = !is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v;
}
if (null === $params) {
parent::__construct($values, false);
return;
}
if (count($values) < count($params)) {
$params = array_slice($params, 0, count($values));
} elseif (count($values) > count($params)) {
$values[] = new EnumStub(array_splice($values, count($params)), false);
$params[] = $variadic;
}
if (array('...') === $params) {
$this->dumpKeys = false;
$this->value = $values[0]->value;
} else {
$this->value = array_combine($params, $values);
}
}
private static function getParameters($function, $class)
{
if (isset(self::$parameters[$k = $class.'::'.$function])) {
return self::$parameters[$k];
}
try {
$r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function);
} catch (\ReflectionException $e) {
return array(null, null);
}
$variadic = '...';
$params = array();
foreach ($r->getParameters() as $v) {
$k = '$'.$v->name;
if ($v->isPassedByReference()) {
$k = '&'.$k;
}
if (method_exists($v, 'isVariadic') && $v->isVariadic()) {
$variadic .= $k;
} else {
$params[] = $k;
}
}
return self::$parameters[$k] = array($variadic, $params);
}
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\VarDumper\Caster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
* Helper for filtering out properties in casters.
*
@ -18,99 +20,123 @@ namespace Symfony\Component\VarDumper\Caster;
*/
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;
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;
const PREFIX_VIRTUAL = "\0~\0";
const PREFIX_DYNAMIC = "\0+\0";
const PREFIX_PROTECTED = "\0*\0";
const PREFIX_VIRTUAL = "\0~\0";
const PREFIX_DYNAMIC = "\0+\0";
const PREFIX_PROTECTED = "\0*\0";
/**
* Casts objects to arrays and adds the dynamic property prefix.
*
* @param object $obj The object to cast.
* @param \ReflectionClass $reflector The class reflector to use for inspecting the object definition.
*
* @return array The array-cast of the object, with prefixed dynamic properties.
*/
public static function castObject($obj, \ReflectionClass $reflector)
{
if ($reflector->hasMethod('__debugInfo')) {
$a = $obj->__debugInfo();
} else {
$a = (array) $obj;
}
/**
* Casts objects to arrays and adds the dynamic property prefix.
*
* @param object $obj The object to cast
* @param \ReflectionClass $reflector The class reflector to use for inspecting the object definition
*
* @return array The array-cast of the object, with prefixed dynamic properties
*/
public static function castObject($obj, \ReflectionClass $reflector)
{
if ($reflector->hasMethod('__debugInfo')) {
$a = $obj->__debugInfo();
} elseif ($obj instanceof \Closure) {
$a = array();
} else {
$a = (array) $obj;
}
if ($obj instanceof \__PHP_Incomplete_Class) {
return $a;
}
if ($a) {
$p = array_keys($a);
foreach ($p as $i => $k) {
if (!isset($k[0]) || ("\0" !== $k[0] && !$reflector->hasProperty($k))) {
$p[$i] = self::PREFIX_DYNAMIC.$k;
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
$p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0");
}
}
$a = array_combine($p, $a);
}
if ($a) {
$combine = false;
$p = array_keys($a);
foreach ($p as $i => $k) {
if (isset($k[0]) ? "\0" !== $k[0] && !$reflector->hasProperty($k) : \PHP_VERSION_ID >= 70200) {
$combine = true;
$p[$i] = self::PREFIX_DYNAMIC.$k;
} elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) {
$combine = true;
$p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0");
}
}
if ($combine) {
$a = array_combine($p, $a);
}
}
return $a;
}
return $a;
}
/**
* Filters out the specified properties.
*
* By default, a single match in the $filter bit field filters properties out, following an "or" logic.
* When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed.
*
* @param array $a The array containing the properties to filter.
* @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out.
* @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set.
*
* @return array The filtered array
*/
public static function filter(array $a, $filter, array $listedProperties = array())
{
foreach ($a as $k => $v) {
$type = self::EXCLUDE_STRICT & $filter;
/**
* Filters out the specified properties.
*
* By default, a single match in the $filter bit field filters properties out, following an "or" logic.
* When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed.
*
* @param array $a The array containing the properties to filter
* @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out
* @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set
* @param int &$count Set to the number of removed properties
*
* @return array The filtered array
*/
public static function filter(array $a, $filter, array $listedProperties = array(), &$count = 0)
{
$count = 0;
if (null === $v) {
$type |= self::EXCLUDE_NULL & $filter;
}
if (empty($v)) {
$type |= self::EXCLUDE_EMPTY & $filter;
}
if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_NOT_IMPORTANT;
}
if ((self::EXCLUDE_VERBOSE & $filter) && in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_VERBOSE;
}
foreach ($a as $k => $v) {
$type = self::EXCLUDE_STRICT & $filter;
if (!isset($k[1]) || "\0" !== $k[0]) {
$type |= self::EXCLUDE_PUBLIC & $filter;
} elseif ('~' === $k[1]) {
$type |= self::EXCLUDE_VIRTUAL & $filter;
} elseif ('+' === $k[1]) {
$type |= self::EXCLUDE_DYNAMIC & $filter;
} elseif ('*' === $k[1]) {
$type |= self::EXCLUDE_PROTECTED & $filter;
} else {
$type |= self::EXCLUDE_PRIVATE & $filter;
}
if (null === $v) {
$type |= self::EXCLUDE_NULL & $filter;
}
if (empty($v)) {
$type |= self::EXCLUDE_EMPTY & $filter;
}
if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_NOT_IMPORTANT;
}
if ((self::EXCLUDE_VERBOSE & $filter) && in_array($k, $listedProperties, true)) {
$type |= self::EXCLUDE_VERBOSE;
}
if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) {
unset($a[$k]);
}
}
if (!isset($k[1]) || "\0" !== $k[0]) {
$type |= self::EXCLUDE_PUBLIC & $filter;
} elseif ('~' === $k[1]) {
$type |= self::EXCLUDE_VIRTUAL & $filter;
} elseif ('+' === $k[1]) {
$type |= self::EXCLUDE_DYNAMIC & $filter;
} elseif ('*' === $k[1]) {
$type |= self::EXCLUDE_PROTECTED & $filter;
} else {
$type |= self::EXCLUDE_PRIVATE & $filter;
}
return $a;
}
if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) {
unset($a[$k]);
++$count;
}
}
return $a;
}
public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, $isNested)
{
if (isset($a['__PHP_Incomplete_Class_Name'])) {
$stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')';
unset($a['__PHP_Incomplete_Class_Name']);
}
return $a;
}
}

View File

@ -0,0 +1,87 @@
<?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;
/**
* Represents a PHP class identifier.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class ClassStub extends ConstStub
{
/**
* Constructor.
*
* @param string A PHP identifier, e.g. a class, method, interface, etc. name
* @param callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier
*/
public function __construct($identifier, $callable = null)
{
$this->value = $identifier;
if (0 < $i = strrpos($identifier, '\\')) {
$this->attr['ellipsis'] = strlen($identifier) - $i;
}
try {
if (null !== $callable) {
if ($callable instanceof \Closure) {
$r = new \ReflectionFunction($callable);
} elseif (is_object($callable)) {
$r = array($callable, '__invoke');
} elseif (is_array($callable)) {
$r = $callable;
} elseif (false !== $i = strpos($callable, '::')) {
$r = array(substr($callable, 0, $i), substr($callable, 2 + $i));
} else {
$r = new \ReflectionFunction($callable);
}
} elseif (false !== $i = strpos($identifier, '::')) {
$r = array(substr($identifier, 0, $i), substr($identifier, 2 + $i));
} else {
$r = new \ReflectionClass($identifier);
}
if (is_array($r)) {
try {
$r = new \ReflectionMethod($r[0], $r[1]);
} catch (\ReflectionException $e) {
$r = new \ReflectionClass($r[0]);
}
}
} catch (\ReflectionException $e) {
return;
}
if ($f = $r->getFileName()) {
$this->attr['file'] = $f;
$this->attr['line'] = $r->getStartLine();
}
}
public static function wrapCallable($callable)
{
if (is_object($callable) || !is_callable($callable)) {
return $callable;
}
if (!is_array($callable)) {
$callable = new static($callable);
} elseif (is_string($callable[0])) {
$callable[0] = new static($callable[0]);
} else {
$callable[1] = new static($callable[1], $callable);
}
return $callable;
}
}

View File

@ -20,9 +20,14 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class ConstStub extends Stub
{
public function __construct($name, $value)
{
$this->class = $name;
$this->value = $value;
}
public function __construct($name, $value)
{
$this->class = $name;
$this->value = $value;
}
public function __toString()
{
return (string) $this->value;
}
}

View File

@ -20,37 +20,40 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class CutStub extends Stub
{
public function __construct($value)
{
$this->value = $value;
public function __construct($value)
{
$this->value = $value;
switch (gettype($value)) {
case 'object':
$this->type = self::TYPE_OBJECT;
$this->class = get_class($value);
$this->cut = -1;
break;
switch (gettype($value)) {
case 'object':
$this->type = self::TYPE_OBJECT;
$this->class = get_class($value);
$this->cut = -1;
break;
case 'array':
$this->type = self::TYPE_ARRAY;
$this->class = self::ARRAY_ASSOC;
$this->cut = $this->value = count($value);
break;
case 'array':
$this->type = self::TYPE_ARRAY;
$this->class = self::ARRAY_ASSOC;
$this->cut = $this->value = count($value);
break;
case 'resource':
case 'unknown type':
$this->type = self::TYPE_RESOURCE;
$this->handle = (int) $value;
$this->class = @get_resource_type($value);
$this->cut = -1;
break;
case 'resource':
case 'unknown type':
case 'resource (closed)':
$this->type = self::TYPE_RESOURCE;
$this->handle = (int) $value;
if ('Unknown' === $this->class = @get_resource_type($value)) {
$this->class = 'Closed';
}
$this->cut = -1;
break;
case 'string':
$this->type = self::TYPE_STRING;
$this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY;
$this->cut = self::STRING_BINARY === $this->class ? strlen($value) : mb_strlen($value, 'UTF-8');
$this->value = '';
break;
}
}
case 'string':
$this->type = self::TYPE_STRING;
$this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY;
$this->cut = self::STRING_BINARY === $this->class ? strlen($value) : mb_strlen($value, 'UTF-8');
$this->value = '';
break;
}
}
}

View File

@ -20,283 +20,283 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
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 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 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 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',
);
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]);
}
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]);
}
return $a;
}
return $a;
}
public static function castLength($dom, array $a, Stub $stub, $isNested)
{
$a += array(
'length' => $dom->length,
);
public static function castLength($dom, array $a, Stub $stub, $isNested)
{
$a += array(
'length' => $dom->length,
);
return $a;
}
return $a;
}
public static function castImplementation($dom, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'Core' => '1.0',
Caster::PREFIX_VIRTUAL.'XML' => '2.0',
);
public static function castImplementation($dom, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'Core' => '1.0',
Caster::PREFIX_VIRTUAL.'XML' => '2.0',
);
return $a;
}
return $a;
}
public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$dom->nodeType], $dom->nodeType),
'parentNode' => new CutStub($dom->parentNode),
'childNodes' => $dom->childNodes,
'firstChild' => new CutStub($dom->firstChild),
'lastChild' => new CutStub($dom->lastChild),
'previousSibling' => new CutStub($dom->previousSibling),
'nextSibling' => new CutStub($dom->nextSibling),
'attributes' => $dom->attributes,
'ownerDocument' => new CutStub($dom->ownerDocument),
'namespaceURI' => $dom->namespaceURI,
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'baseURI' => $dom->baseURI,
'textContent' => new CutStub($dom->textContent),
);
public static function castNode(\DOMNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$dom->nodeType], $dom->nodeType),
'parentNode' => new CutStub($dom->parentNode),
'childNodes' => $dom->childNodes,
'firstChild' => new CutStub($dom->firstChild),
'lastChild' => new CutStub($dom->lastChild),
'previousSibling' => new CutStub($dom->previousSibling),
'nextSibling' => new CutStub($dom->nextSibling),
'attributes' => $dom->attributes,
'ownerDocument' => new CutStub($dom->ownerDocument),
'namespaceURI' => $dom->namespaceURI,
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI,
'textContent' => new CutStub($dom->textContent),
);
return $a;
}
return $a;
}
public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$dom->nodeType], $dom->nodeType),
'prefix' => $dom->prefix,
'localName' => $dom->localName,
'namespaceURI' => $dom->namespaceURI,
'ownerDocument' => new CutStub($dom->ownerDocument),
'parentNode' => new CutStub($dom->parentNode),
);
public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'nodeName' => $dom->nodeName,
'nodeValue' => new CutStub($dom->nodeValue),
'nodeType' => new ConstStub(self::$nodeTypes[$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;
}
return $a;
}
public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
'doctype' => $dom->doctype,
'implementation' => $dom->implementation,
'documentElement' => new CutStub($dom->documentElement),
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'xmlEncoding' => $dom->xmlEncoding,
'standalone' => $dom->standalone,
'xmlStandalone' => $dom->xmlStandalone,
'version' => $dom->version,
'xmlVersion' => $dom->xmlVersion,
'strictErrorChecking' => $dom->strictErrorChecking,
'documentURI' => $dom->documentURI,
'config' => $dom->config,
'formatOutput' => $dom->formatOutput,
'validateOnParse' => $dom->validateOnParse,
'resolveExternals' => $dom->resolveExternals,
'preserveWhiteSpace' => $dom->preserveWhiteSpace,
'recover' => $dom->recover,
'substituteEntities' => $dom->substituteEntities,
);
public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, $isNested, $filter = 0)
{
$a += array(
'doctype' => $dom->doctype,
'implementation' => $dom->implementation,
'documentElement' => new CutStub($dom->documentElement),
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'xmlEncoding' => $dom->xmlEncoding,
'standalone' => $dom->standalone,
'xmlStandalone' => $dom->xmlStandalone,
'version' => $dom->version,
'xmlVersion' => $dom->xmlVersion,
'strictErrorChecking' => $dom->strictErrorChecking,
'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI,
'config' => $dom->config,
'formatOutput' => $dom->formatOutput,
'validateOnParse' => $dom->validateOnParse,
'resolveExternals' => $dom->resolveExternals,
'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());
$dom->formatOutput = $formatOutput;
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
$formatOutput = $dom->formatOutput;
$dom->formatOutput = true;
$a += array(Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML());
$dom->formatOutput = $formatOutput;
}
return $a;
}
return $a;
}
public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'data' => $dom->data,
'length' => $dom->length,
);
public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'data' => $dom->data,
'length' => $dom->length,
);
return $a;
}
return $a;
}
public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'name' => $dom->name,
'specified' => $dom->specified,
'value' => $dom->value,
'ownerElement' => $dom->ownerElement,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'name' => $dom->name,
'specified' => $dom->specified,
'value' => $dom->value,
'ownerElement' => $dom->ownerElement,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
return $a;
}
return $a;
}
public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'tagName' => $dom->tagName,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
public static function castElement(\DOMElement $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'tagName' => $dom->tagName,
'schemaTypeInfo' => $dom->schemaTypeInfo,
);
return $a;
}
return $a;
}
public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'wholeText' => $dom->wholeText,
);
public static function castText(\DOMText $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'wholeText' => $dom->wholeText,
);
return $a;
}
return $a;
}
public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'typeName' => $dom->typeName,
'typeNamespace' => $dom->typeNamespace,
);
public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'typeName' => $dom->typeName,
'typeNamespace' => $dom->typeNamespace,
);
return $a;
}
return $a;
}
public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'severity' => $dom->severity,
'message' => $dom->message,
'type' => $dom->type,
'relatedException' => $dom->relatedException,
'related_data' => $dom->related_data,
'location' => $dom->location,
);
public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'severity' => $dom->severity,
'message' => $dom->message,
'type' => $dom->type,
'relatedException' => $dom->relatedException,
'related_data' => $dom->related_data,
'location' => $dom->location,
);
return $a;
}
return $a;
}
public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'lineNumber' => $dom->lineNumber,
'columnNumber' => $dom->columnNumber,
'offset' => $dom->offset,
'relatedNode' => $dom->relatedNode,
'uri' => $dom->uri,
);
public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'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;
}
return $a;
}
public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'name' => $dom->name,
'entities' => $dom->entities,
'notations' => $dom->notations,
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'internalSubset' => $dom->internalSubset,
);
public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'name' => $dom->name,
'entities' => $dom->entities,
'notations' => $dom->notations,
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'internalSubset' => $dom->internalSubset,
);
return $a;
}
return $a;
}
public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
);
public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
);
return $a;
}
return $a;
}
public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'notationName' => $dom->notationName,
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'version' => $dom->version,
);
public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'publicId' => $dom->publicId,
'systemId' => $dom->systemId,
'notationName' => $dom->notationName,
'actualEncoding' => $dom->actualEncoding,
'encoding' => $dom->encoding,
'version' => $dom->version,
);
return $a;
}
return $a;
}
public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'target' => $dom->target,
'data' => $dom->data,
);
public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'target' => $dom->target,
'data' => $dom->data,
);
return $a;
}
return $a;
}
public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'document' => $dom->document,
);
public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, $isNested)
{
$a += array(
'document' => $dom->document,
);
return $a;
}
return $a;
}
}

View File

@ -20,8 +20,11 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class EnumStub extends Stub
{
public function __construct(array $values)
{
$this->value = $values;
}
public $dumpKeys = true;
public function __construct(array $values, $dumpKeys = true)
{
$this->value = $values;
$this->dumpKeys = $dumpKeys;
}
}

View File

@ -21,218 +21,278 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
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 $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 function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
}
private static $framesCache = array();
public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter);
}
public static function castError(\Error $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter);
}
public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested)
{
if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) {
$a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
}
public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
{
return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter);
}
return $a;
}
public static function castErrorException(\ErrorException $e, array $a, Stub $stub, $isNested)
{
if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) {
$a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]);
}
public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_PROTECTED;
$xPrefix = "\0Exception\0";
return $a;
}
if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'])) {
$b = (array) $a[$xPrefix.'previous'];
array_unshift($b[$xPrefix.'trace'], array(
'function' => 'new '.get_class($a[$xPrefix.'previous']),
'file' => $b[$prefix.'file'],
'line' => $b[$prefix.'line'],
));
$a[$xPrefix.'trace'] = new TraceStub($b[$xPrefix.'trace'], false, 0, -1 - count($a[$xPrefix.'trace']->value));
}
public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_PROTECTED;
$xPrefix = "\0Exception\0";
unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']);
if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace']) && $a[$xPrefix.'previous'] instanceof \Exception) {
$b = (array) $a[$xPrefix.'previous'];
self::traceUnshift($b[$xPrefix.'trace'], get_class($a[$xPrefix.'previous']), $b[$prefix.'file'], $b[$prefix.'line']);
$a[$xPrefix.'trace'] = new TraceStub($b[$xPrefix.'trace'], false, 0, -1 - count($a[$xPrefix.'trace']->value));
}
return $a;
}
unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']);
public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$stub->class = '';
$stub->handle = 0;
$frames = $trace->value;
return $a;
}
$a = array();
$j = count($frames);
if (0 > $i = $trace->sliceOffset) {
$i = max(0, $j + $i);
}
if (!isset($trace->value[$i])) {
return array();
}
$lastCall = isset($frames[$i]['function']) ? ' ==> '.(isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '';
public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$stub->class = '';
$stub->handle = 0;
$frames = $trace->value;
$prefix = Caster::PREFIX_VIRTUAL;
for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
$call = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[$i]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '???';
$a = array();
$j = count($frames);
if (0 > $i = $trace->sliceOffset) {
$i = max(0, $j + $i);
}
if (!isset($trace->value[$i])) {
return array();
}
$lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : '';
$frames[] = array('function' => '');
$a[Caster::PREFIX_VIRTUAL.$j.'. '.$call.$lastCall] = new FrameStub(
array(
'object' => isset($frames[$i]['object']) ? $frames[$i]['object'] : null,
'class' => isset($frames[$i]['class']) ? $frames[$i]['class'] : null,
'type' => isset($frames[$i]['type']) ? $frames[$i]['type'] : null,
'function' => isset($frames[$i]['function']) ? $frames[$i]['function'] : null,
) + $frames[$i - 1],
$trace->keepArgs,
true
);
for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) {
$f = $frames[$i];
$call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'].'()' : '???';
$lastCall = ' ==> '.$call;
}
$a[Caster::PREFIX_VIRTUAL.$j.'. {main}'.$lastCall] = new FrameStub(
array(
'object' => null,
'class' => null,
'type' => null,
'function' => '{main}',
) + $frames[$i - 1],
$trace->keepArgs,
true
);
if (null !== $trace->sliceLength) {
$a = array_slice($a, 0, $trace->sliceLength, true);
}
$label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall;
$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],
false,
true
);
$f = self::castFrameStub($frame, array(), $frame, true);
if (isset($f[$prefix.'src'])) {
foreach ($f[$prefix.'src']->value as $label => $frame) {
$label = substr_replace($label, "title=Stack level $j.&", 2, 0);
}
$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);
}
}
$a[$label] = $frame;
return $a;
}
$lastCall = $call;
}
if (null !== $trace->sliceLength) {
$a = array_slice($a, 0, $trace->sliceLength, true);
}
public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$f = $frame->value;
$prefix = Caster::PREFIX_VIRTUAL;
return $a;
}
if (isset($f['file'], $f['line'])) {
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
$f['file'] = substr($f['file'], 0, -strlen($match[0]));
$f['line'] = (int) $match[1];
}
if (file_exists($f['file']) && 0 <= self::$srcContext) {
$src[$f['file'].':'.$f['line']] = self::extractSource(explode("\n", file_get_contents($f['file'])), $f['line'], self::$srcContext);
public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $isNested)
{
if (!$isNested) {
return $a;
}
$f = $frame->value;
$prefix = Caster::PREFIX_VIRTUAL;
if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) {
$template = isset($f['object']) ? $f['object'] : new $f['class'](new \Twig_Environment(new \Twig_Loader_Filesystem()));
if (isset($f['file'], $f['line'])) {
$cacheKey = $f;
unset($cacheKey['object'], $cacheKey['args']);
$cacheKey[] = self::$srcContext;
$cacheKey = implode('-', $cacheKey);
try {
$templateName = $template->getTemplateName();
$templateSrc = explode("\n", method_exists($template, 'getSource') ? $template->getSource() : $template->getEnvironment()->getLoader()->getSource($templateName));
$templateInfo = $template->getDebugInfo();
if (isset($templateInfo[$f['line']])) {
$src[$templateName.':'.$templateInfo[$f['line']]] = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext);
}
} catch (\Twig_Error_Loader $e) {
}
}
} else {
$src[$f['file']] = $f['line'];
}
$a[$prefix.'src'] = new EnumStub($src);
}
if (isset(self::$framesCache[$cacheKey])) {
$a[$prefix.'src'] = self::$framesCache[$cacheKey];
} else {
if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) {
$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 = explode(DIRECTORY_SEPARATOR, $srcKey);
$ellipsis = 3 < count($ellipsis) ? 2 + strlen(implode(array_slice($ellipsis, -2))) : 0;
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
if ($frame->inTraceStub) {
unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']);
}
foreach ($a as $k => $v) {
if (!$v) {
unset($a[$k]);
}
}
if ($frame->keepArgs && isset($f['args'])) {
$a[$prefix.'args'] = $f['args'];
}
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']));
return $a;
}
$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']];
}
}
}
if ($srcKey == $f['file']) {
$src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, $caller, 'php', $f['file']);
$srcKey .= ':'.$f['line'];
if ($ellipsis) {
$ellipsis += 1 + strlen($f['line']);
}
}
}
$srcAttr = $ellipsis ? 'ellipsis='.$ellipsis : '';
self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(array("\0~$srcAttr\0$srcKey" => $src));
}
}
private static function filterExceptionArray($xClass, array $a, $xPrefix, $filter)
{
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
}
unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']);
if ($frame->inTraceStub) {
unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']);
}
foreach ($a as $k => $v) {
if (!$v) {
unset($a[$k]);
}
}
if ($frame->keepArgs && !empty($f['args'])) {
$a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']);
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
array_unshift($trace, array(
'function' => $xClass ? 'new '.$xClass : null,
'file' => $a[Caster::PREFIX_PROTECTED.'file'],
'line' => $a[Caster::PREFIX_PROTECTED.'line'],
));
$a[$xPrefix.'trace'] = new TraceStub($trace);
}
if (empty($a[$xPrefix.'previous'])) {
unset($a[$xPrefix.'previous']);
}
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
return $a;
}
return $a;
}
private static function filterExceptionArray($xClass, array $a, $xPrefix, $filter)
{
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
}
private static function extractSource(array $srcArray, $line, $srcContext)
{
$src = array();
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) {
self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']);
}
$a[$xPrefix.'trace'] = new TraceStub($trace, self::$traceArgs);
}
if (empty($a[$xPrefix.'previous'])) {
unset($a[$xPrefix.'previous']);
}
unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']);
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
$src[] = (isset($srcArray[$i]) ? $srcArray[$i] : '')."\n";
}
if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) {
$a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']);
}
$ltrim = 0;
while (' ' === $src[0][$ltrim] || "\t" === $src[0][$ltrim]) {
$i = $srcContext << 1;
while ($i > 0 && $src[0][$ltrim] === $src[$i][$ltrim]) {
--$i;
}
if ($i) {
break;
}
++$ltrim;
}
if ($ltrim) {
foreach ($src as $i => $line) {
$src[$i] = substr($line, $ltrim);
}
}
return $a;
}
return implode('', $src);
}
private static function traceUnshift(&$trace, $class, $file, $line)
{
if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) {
return;
}
array_unshift($trace, array(
'function' => $class ? 'new '.$class : null,
'file' => $file,
'line' => $line,
));
}
private static function extractSource($srcLines, $line, $srcContext, $title, $lang, $file = null)
{
$srcLines = explode("\n", $srcLines);
$src = array();
for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) {
$src[] = (isset($srcLines[$i]) ? $srcLines[$i] : '')."\n";
}
$srcLines = array();
$ltrim = 0;
do {
$pad = null;
for ($i = $srcContext << 1; $i >= 0; --$i) {
if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) {
if (null === $pad) {
$pad = $c;
}
if ((' ' !== $c && "\t" !== $c) || $pad !== $c) {
break;
}
}
}
++$ltrim;
} while (0 > $i && null !== $pad);
--$ltrim;
foreach ($src as $i => $c) {
if ($ltrim) {
$c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? substr($c, $ltrim) : ltrim($c, " \t");
}
$c = substr($c, 0, -1);
if ($i !== $srcContext) {
$c = new ConstStub('default', $c);
} else {
$c = new ConstStub($c, $title);
if (null !== $file) {
$c->attr['file'] = $file;
$c->attr['line'] = $line;
}
}
$c->attr['lang'] = $lang;
$srcLines[sprintf("\0~%d\0", $i + $line - $srcContext)] = $c;
}
return new EnumStub($srcLines);
}
}

View File

@ -0,0 +1,51 @@
<?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;
/**
* Represents a file or a URL.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class LinkStub extends ConstStub
{
public function __construct($label, $line = 0, $href = null)
{
$this->value = $label;
if (null === $href) {
$href = $label;
}
if (is_string($href)) {
if (0 === strpos($href, 'file://')) {
if ($href === $label) {
$label = substr($label, 7);
}
$href = substr($href, 7);
} elseif (false !== strpos($href, '://')) {
$this->attr['href'] = $href;
return;
}
if (file_exists($href)) {
if ($line) {
$this->attr['line'] = $line;
}
$this->attr['file'] = realpath($href) ?: $href;
if ($this->attr['file'] === $label && 3 < count($ellipsis = explode(DIRECTORY_SEPARATOR, $href))) {
$this->attr['ellipsis'] = 2 + strlen(implode(array_slice($ellipsis, -2)));
}
}
}
}
}

View File

@ -20,95 +20,101 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class PdoCaster
{
private static $pdoAttributes = array(
'CASE' => array(
\PDO::CASE_LOWER => 'LOWER',
\PDO::CASE_NATURAL => 'NATURAL',
\PDO::CASE_UPPER => 'UPPER',
),
'ERRMODE' => array(
\PDO::ERRMODE_SILENT => 'SILENT',
\PDO::ERRMODE_WARNING => 'WARNING',
\PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
),
'TIMEOUT',
'PREFETCH',
'AUTOCOMMIT',
'PERSISTENT',
'DRIVER_NAME',
'SERVER_INFO',
'ORACLE_NULLS' => array(
\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(
\PDO::FETCH_ASSOC => 'ASSOC',
\PDO::FETCH_BOTH => 'BOTH',
\PDO::FETCH_LAZY => 'LAZY',
\PDO::FETCH_NUM => 'NUM',
\PDO::FETCH_OBJ => 'OBJ',
),
);
private static $pdoAttributes = array(
'CASE' => array(
\PDO::CASE_LOWER => 'LOWER',
\PDO::CASE_NATURAL => 'NATURAL',
\PDO::CASE_UPPER => 'UPPER',
),
'ERRMODE' => array(
\PDO::ERRMODE_SILENT => 'SILENT',
\PDO::ERRMODE_WARNING => 'WARNING',
\PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
),
'TIMEOUT',
'PREFETCH',
'AUTOCOMMIT',
'PERSISTENT',
'DRIVER_NAME',
'SERVER_INFO',
'ORACLE_NULLS' => array(
\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(
\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();
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
public static function castPdo(\PDO $c, array $a, Stub $stub, $isNested)
{
$attr = array();
$errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
$c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
foreach (self::$pdoAttributes as $k => $v) {
if (!isset($k[0])) {
$k = $v;
$v = array();
}
foreach (self::$pdoAttributes as $k => $v) {
if (!isset($k[0])) {
$k = $v;
$v = array();
}
try {
$attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(constant('PDO::ATTR_'.$k));
if ($v && isset($v[$attr[$k]])) {
$attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]);
}
} catch (\Exception $e) {
}
}
try {
$attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(constant('PDO::ATTR_'.$k));
if ($v && isset($v[$attr[$k]])) {
$attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]);
}
} catch (\Exception $e) {
}
}
if (isset($attr[$k = 'STATEMENT_CLASS'][1])) {
if ($attr[$k][1]) {
$attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]);
}
$attr[$k][0] = new ClassStub($attr[$k][0]);
}
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$prefix.'inTransaction' => method_exists($c, 'inTransaction'),
$prefix.'errorInfo' => $c->errorInfo(),
$prefix.'attributes' => new EnumStub($attr),
);
$prefix = Caster::PREFIX_VIRTUAL;
$a += array(
$prefix.'inTransaction' => method_exists($c, 'inTransaction'),
$prefix.'errorInfo' => $c->errorInfo(),
$prefix.'attributes' => new EnumStub($attr),
);
if ($a[$prefix.'inTransaction']) {
$a[$prefix.'inTransaction'] = $c->inTransaction();
} else {
unset($a[$prefix.'inTransaction']);
}
if ($a[$prefix.'inTransaction']) {
$a[$prefix.'inTransaction'] = $c->inTransaction();
} else {
unset($a[$prefix.'inTransaction']);
}
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
$c->setAttribute(\PDO::ATTR_ERRMODE, $errmode);
$c->setAttribute(\PDO::ATTR_ERRMODE, $errmode);
return $a;
}
return $a;
}
public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a[$prefix.'errorInfo'] = $c->errorInfo();
public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$a[$prefix.'errorInfo'] = $c->errorInfo();
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) {
unset($a[$prefix.'errorInfo']);
}
return $a;
}
return $a;
}
}

View File

@ -0,0 +1,77 @@
<?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;
/**
* Casts Redis class from ext-redis to array representation.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class RedisCaster
{
private static $serializer = array(
\Redis::SERIALIZER_NONE => 'NONE',
\Redis::SERIALIZER_PHP => 'PHP',
2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY
);
public static function castRedis(\Redis $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if (defined('HHVM_VERSION_ID')) {
if (isset($a[Caster::PREFIX_PROTECTED.'serializer'])) {
$ser = $a[Caster::PREFIX_PROTECTED.'serializer'];
$a[Caster::PREFIX_PROTECTED.'serializer'] = isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser;
}
return $a;
}
if (!$connected = $c->isConnected()) {
return $a + array(
$prefix.'isConnected' => $connected,
);
}
$ser = $c->getOption(\Redis::OPT_SERIALIZER);
$retry = defined('Redis::OPT_SCAN') ? $c->getOption(\Redis::OPT_SCAN) : 0;
return $a + array(
$prefix.'isConnected' => $connected,
$prefix.'host' => $c->getHost(),
$prefix.'port' => $c->getPort(),
$prefix.'auth' => $c->getAuth(),
$prefix.'dbNum' => $c->getDbNum(),
$prefix.'timeout' => $c->getTimeout(),
$prefix.'persistentId' => $c->getPersistentID(),
$prefix.'options' => new EnumStub(array(
'READ_TIMEOUT' => $c->getOption(\Redis::OPT_READ_TIMEOUT),
'SERIALIZER' => isset(self::$serializer[$ser]) ? new ConstStub(self::$serializer[$ser], $ser) : $ser,
'PREFIX' => $c->getOption(\Redis::OPT_PREFIX),
'SCAN' => new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry),
)),
);
}
public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a + array(
$prefix.'hosts' => $c->_hosts(),
$prefix.'function' => ClassStub::wrapCallable($c->_function()),
);
}
}

View File

@ -20,291 +20,313 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class ReflectionCaster
{
private static $extraMap = array(
'docComment' => 'getDocComment',
'extension' => 'getExtensionName',
'isDisabled' => 'isDisabled',
'isDeprecated' => 'isDeprecated',
'isInternal' => 'isInternal',
'isUserDefined' => 'isUserDefined',
'isGenerator' => 'isGenerator',
'isVariadic' => 'isVariadic',
);
private static $extraMap = array(
'docComment' => 'getDocComment',
'extension' => 'getExtensionName',
'isDisabled' => 'isDisabled',
'isDeprecated' => 'isDeprecated',
'isInternal' => 'isInternal',
'isUserDefined' => 'isUserDefined',
'isGenerator' => 'isGenerator',
'isVariadic' => 'isVariadic',
);
public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$c = new \ReflectionFunction($c);
public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$c = new \ReflectionFunction($c);
$stub->class = 'Closure'; // HHVM generates unique class names for closures
$a = static::castFunctionAbstract($c, $a, $stub, $isNested);
$stub->class = 'Closure'; // HHVM generates unique class names for closures
$a = static::castFunctionAbstract($c, $a, $stub, $isNested);
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 (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()) {
$a[$prefix.'file'] = $f;
$a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine();
}
if ($f = $c->getFileName()) {
$a[$prefix.'file'] = new LinkStub($f, $c->getStartLine());
$a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine();
}
$prefix = Caster::PREFIX_DYNAMIC;
unset($a['name'], $a[$prefix.'0'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']);
$prefix = Caster::PREFIX_DYNAMIC;
unset($a['name'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']);
return $a;
}
return $a;
}
public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested)
{
return class_exists('ReflectionGenerator', false) ? self::castReflectionGenerator(new \ReflectionGenerator($c), $a, $stub, $isNested) : $a;
}
public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested)
{
if (!class_exists('ReflectionGenerator', false)) {
return $a;
}
public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
// Cannot create ReflectionGenerator based on a terminated Generator
try {
$reflectionGenerator = new \ReflectionGenerator($c);
} catch (\Exception $e) {
$a[Caster::PREFIX_VIRTUAL.'closed'] = true;
$a += array(
$prefix.'type' => $c->__toString(),
$prefix.'allowsNull' => $c->allowsNull(),
$prefix.'isBuiltin' => $c->isBuiltin(),
);
return $a;
}
return $a;
}
return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested);
}
public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if ($c->getThis()) {
$a[$prefix.'this'] = new CutStub($c->getThis());
}
$x = $c->getFunction();
$frame = array(
'class' => isset($x->class) ? $x->class : null,
'type' => isset($x->class) ? ($x->isStatic() ? '::' : '->') : null,
'function' => $x->name,
'file' => $c->getExecutingFile(),
'line' => $c->getExecutingLine(),
);
if ($trace = $c->getTrace(DEBUG_BACKTRACE_IGNORE_ARGS)) {
$x = new \ReflectionGenerator($c->getExecutingGenerator());
array_unshift($trace, array(
'function' => 'yield',
'file' => $x->getExecutingFile(),
'line' => $x->getExecutingLine() - 1,
));
$trace[] = $frame;
$a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1);
} else {
$x = new FrameStub($frame, false, true);
$x = ExceptionCaster::castFrameStub($x, array(), $x, true);
$a[$prefix.'executing'] = new EnumStub(array(
$frame['class'].$frame['type'].$frame['function'].'()' => $x[$prefix.'src'],
));
}
$a += array(
$prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(),
$prefix.'allowsNull' => $c->allowsNull(),
$prefix.'isBuiltin' => $c->isBuiltin(),
);
return $a;
}
return $a;
}
public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
if ($n = \Reflection::getModifierNames($c->getModifiers())) {
$a[$prefix.'modifiers'] = implode(' ', $n);
}
if ($c->getThis()) {
$a[$prefix.'this'] = new CutStub($c->getThis());
}
$function = $c->getFunction();
$frame = array(
'class' => isset($function->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)) {
$function = new \ReflectionGenerator($c->getExecutingGenerator());
array_unshift($trace, array(
'function' => 'yield',
'file' => $function->getExecutingFile(),
'line' => $function->getExecutingLine() - 1,
));
$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(
$frame['class'].$frame['type'].$frame['function'].'()' => $function[$prefix.'src'],
));
}
self::addMap($a, $c, array(
'extends' => 'getParentClass',
'implements' => 'getInterfaceNames',
'constants' => 'getConstants',
));
$a[Caster::PREFIX_VIRTUAL.'closed'] = false;
foreach ($c->getProperties() as $n) {
$a[$prefix.'properties'][$n->name] = $n;
}
return $a;
}
foreach ($c->getMethods() as $n) {
$a[$prefix.'methods'][$n->name] = $n;
}
public static function castClass(\ReflectionClass $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
if ($n = \Reflection::getModifierNames($c->getModifiers())) {
$a[$prefix.'modifiers'] = implode(' ', $n);
}
return $a;
}
self::addMap($a, $c, array(
'extends' => 'getParentClass',
'implements' => 'getInterfaceNames',
'constants' => 'getConstants',
));
public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
foreach ($c->getProperties() as $n) {
$a[$prefix.'properties'][$n->name] = $n;
}
self::addMap($a, $c, array(
'returnsReference' => 'returnsReference',
'returnType' => 'getReturnType',
'class' => 'getClosureScopeClass',
'this' => 'getClosureThis',
));
foreach ($c->getMethods() as $n) {
$a[$prefix.'methods'][$n->name] = $n;
}
if (isset($a[$prefix.'returnType'])) {
$a[$prefix.'returnType'] = (string) $a[$prefix.'returnType'];
}
if (isset($a[$prefix.'this'])) {
$a[$prefix.'this'] = new CutStub($a[$prefix.'this']);
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
foreach ($c->getParameters() as $v) {
$k = '$'.$v->name;
if ($v->isPassedByReference()) {
$k = '&'.$k;
}
if (method_exists($v, 'isVariadic') && $v->isVariadic()) {
$k = '...'.$k;
}
$a[$prefix.'parameters'][$k] = $v;
}
if (isset($a[$prefix.'parameters'])) {
$a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']);
}
return $a;
}
if ($v = $c->getStaticVariables()) {
foreach ($v as $k => &$v) {
$a[$prefix.'use']['$'.$k] = &$v;
}
unset($v);
$a[$prefix.'use'] = new EnumStub($a[$prefix.'use']);
}
public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, $isNested, $filter = 0)
{
$prefix = Caster::PREFIX_VIRTUAL;
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
self::addMap($a, $c, array(
'returnsReference' => 'returnsReference',
'returnType' => 'getReturnType',
'class' => 'getClosureScopeClass',
'this' => 'getClosureThis',
));
// Added by HHVM
unset($a[Caster::PREFIX_DYNAMIC.'static']);
if (isset($a[$prefix.'returnType'])) {
$v = $a[$prefix.'returnType'];
$v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString();
$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 : '', ''));
}
if (isset($a[$prefix.'class'])) {
$a[$prefix.'class'] = new ClassStub($a[$prefix.'class']);
}
if (isset($a[$prefix.'this'])) {
$a[$prefix.'this'] = new CutStub($a[$prefix.'this']);
}
return $a;
}
foreach ($c->getParameters() as $v) {
$k = '$'.$v->name;
if (method_exists($v, 'isVariadic') && $v->isVariadic()) {
$k = '...'.$k;
}
if ($v->isPassedByReference()) {
$k = '&'.$k;
}
$a[$prefix.'parameters'][$k] = $v;
}
if (isset($a[$prefix.'parameters'])) {
$a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']);
}
public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
if ($v = $c->getStaticVariables()) {
foreach ($v as $k => &$v) {
$a[$prefix.'use']['$'.$k] = &$v;
}
unset($v);
$a[$prefix.'use'] = new EnumStub($a[$prefix.'use']);
}
return $a;
}
if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) {
self::addExtra($a, $c);
}
public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
// Added by HHVM
unset($a[Caster::PREFIX_DYNAMIC.'static']);
// Added by HHVM
unset($a['info']);
return $a;
}
self::addMap($a, $c, array(
'position' => 'getPosition',
'isVariadic' => 'isVariadic',
'byReference' => 'isPassedByReference',
));
public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
try {
if (method_exists($c, 'hasType')) {
if ($c->hasType()) {
$a[$prefix.'typeHint'] = $c->getType()->__toString();
}
} elseif ($c->isArray()) {
$a[$prefix.'typeHint'] = 'array';
} elseif (method_exists($c, 'isCallable') && $c->isCallable()) {
$a[$prefix.'typeHint'] = 'callable';
} elseif ($v = $c->getClass()) {
$a[$prefix.'typeHint'] = $v->name;
}
} catch (\ReflectionException $e) {
if (preg_match('/^Class ([^ ]++) does not exist$/', $e->getMessage(), $m)) {
$a[$prefix.'typeHint'] = $m[1];
}
}
return $a;
}
try {
$a[$prefix.'default'] = $v = $c->getDefaultValue();
if (method_exists($c, 'isDefaultValueConstant') && $c->isDefaultValueConstant()) {
$a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
}
} catch (\ReflectionException $e) {
if (isset($a[$prefix.'typeHint']) && $c->allowsNull()) {
$a[$prefix.'default'] = null;
}
}
public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
return $a;
}
// Added by HHVM
unset($a['info']);
public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
self::addExtra($a, $c);
self::addMap($a, $c, array(
'position' => 'getPosition',
'isVariadic' => 'isVariadic',
'byReference' => 'isPassedByReference',
'allowsNull' => 'allowsNull',
));
return $a;
}
if (method_exists($c, 'getType')) {
if ($v = $c->getType()) {
$a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString();
}
} elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) {
$a[$prefix.'typeHint'] = $v[1];
}
public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
'version' => 'getVersion',
'dependencies' => 'getDependencies',
'iniEntries' => 'getIniEntries',
'isPersistent' => 'isPersistent',
'isTemporary' => 'isTemporary',
'constants' => 'getConstants',
'functions' => 'getFunctions',
'classes' => 'getClasses',
));
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 : '', ''));
} else {
unset($a[$prefix.'allowsNull']);
}
return $a;
}
try {
$a[$prefix.'default'] = $v = $c->getDefaultValue();
if (method_exists($c, 'isDefaultValueConstant') && $c->isDefaultValueConstant()) {
$a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v);
}
if (null === $v) {
unset($a[$prefix.'allowsNull']);
}
} catch (\ReflectionException $e) {
if (isset($a[$prefix.'typeHint']) && $c->allowsNull() && !class_exists('ReflectionNamedType', false)) {
$a[$prefix.'default'] = null;
unset($a[$prefix.'allowsNull']);
}
}
public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
'version' => 'getVersion',
'author' => 'getAuthor',
'copyright' => 'getCopyright',
'url' => 'getURL',
));
return $a;
}
return $a;
}
public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers()));
self::addExtra($a, $c);
private static function addExtra(&$a, \Reflector $c)
{
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : array();
return $a;
}
if (method_exists($c, 'getFileName') && $m = $c->getFileName()) {
$x['file'] = $m;
$x['line'] = $c->getStartLine().' to '.$c->getEndLine();
}
public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
'version' => 'getVersion',
'dependencies' => 'getDependencies',
'iniEntries' => 'getIniEntries',
'isPersistent' => 'isPersistent',
'isTemporary' => 'isTemporary',
'constants' => 'getConstants',
'functions' => 'getFunctions',
'classes' => 'getClasses',
));
self::addMap($x, $c, self::$extraMap, '');
return $a;
}
if ($x) {
$a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x);
}
}
public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, $isNested)
{
self::addMap($a, $c, array(
'version' => 'getVersion',
'author' => 'getAuthor',
'copyright' => 'getCopyright',
'url' => 'getURL',
));
private static function addMap(&$a, \Reflector $c, $map, $prefix = Caster::PREFIX_VIRTUAL)
{
foreach ($map as $k => $m) {
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
}
}
}
return $a;
}
private static function addExtra(&$a, \Reflector $c)
{
$x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : array();
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, '');
if ($x) {
$a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x);
}
}
private static function addMap(&$a, \Reflector $c, $map, $prefix = Caster::PREFIX_VIRTUAL)
{
foreach ($map as $k => $m) {
if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) {
$a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m;
}
}
}
}

View File

@ -20,48 +20,53 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class ResourceCaster
{
public static function castCurl($h, array $a, Stub $stub, $isNested)
{
return curl_getinfo($h);
}
public static function castCurl($h, array $a, Stub $stub, $isNested)
{
return curl_getinfo($h);
}
public static function castDba($dba, array $a, Stub $stub, $isNested)
{
$list = dba_list();
$a['file'] = $list[(int) $dba];
public static function castDba($dba, array $a, Stub $stub, $isNested)
{
$list = dba_list();
$a['file'] = $list[(int) $dba];
return $a;
}
return $a;
}
public static function castProcess($process, array $a, Stub $stub, $isNested)
{
return proc_get_status($process);
}
public static function castProcess($process, array $a, Stub $stub, $isNested)
{
return proc_get_status($process);
}
public static function castStream($stream, array $a, Stub $stub, $isNested)
{
return stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested);
}
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'])) {
$a['uri'] = new LinkStub($a['uri']);
}
public static function castStreamContext($stream, array $a, Stub $stub, $isNested)
{
return stream_context_get_params($stream);
}
return $a;
}
public static function castGd($gd, array $a, Stub $stub, $isNested)
{
$a['size'] = imagesx($gd).'x'.imagesy($gd);
$a['trueColor'] = imageistruecolor($gd);
public static function castStreamContext($stream, array $a, Stub $stub, $isNested)
{
return @stream_context_get_params($stream) ?: $a;
}
return $a;
}
public static function castGd($gd, array $a, Stub $stub, $isNested)
{
$a['size'] = imagesx($gd).'x'.imagesy($gd);
$a['trueColor'] = imageistruecolor($gd);
public static function castMysqlLink($h, array $a, Stub $stub, $isNested)
{
$a['host'] = mysql_get_host_info($h);
$a['protocol'] = mysql_get_proto_info($h);
$a['server'] = mysql_get_server_info($h);
return $a;
}
return $a;
}
public static function castMysqlLink($h, array $a, Stub $stub, $isNested)
{
$a['host'] = mysql_get_host_info($h);
$a['protocol'] = mysql_get_proto_info($h);
$a['server'] = mysql_get_server_info($h);
return $a;
}
}

View File

@ -20,184 +20,188 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class SplCaster
{
private static $splFileObjectFlags = array(
\SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE',
\SplFileObject::READ_AHEAD => 'READ_AHEAD',
\SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY',
\SplFileObject::READ_CSV => 'READ_CSV',
);
private static $splFileObjectFlags = array(
\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)
{
$prefix = Caster::PREFIX_VIRTUAL;
$class = $stub->class;
$flags = $c->getFlags();
public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$class = $stub->class;
$flags = $c->getFlags();
$b = array(
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
$prefix.'iteratorClass' => $c->getIteratorClass(),
$prefix.'storage' => $c->getArrayCopy(),
);
$b = array(
$prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST),
$prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS),
$prefix.'iteratorClass' => new ClassStub($c->getIteratorClass()),
$prefix.'storage' => $c->getArrayCopy(),
);
if ($class === 'ArrayObject') {
$a = $b;
} else {
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
$c->setFlags(\ArrayObject::STD_PROP_LIST);
$a = Caster::castObject($c, new \ReflectionClass($class));
$c->setFlags($flags);
}
if ($class === 'ArrayObject') {
$a = $b;
} else {
if (!($flags & \ArrayObject::STD_PROP_LIST)) {
$c->setFlags(\ArrayObject::STD_PROP_LIST);
$a = Caster::castObject($c, new \ReflectionClass($class));
$c->setFlags($flags);
}
$a += $b;
}
$a += $b;
}
return $a;
}
return $a;
}
public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c),
);
public static function castHeap(\Iterator $c, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c),
);
return $a;
}
return $a;
}
public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$mode = $c->getIteratorMode();
$c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, $isNested)
{
$prefix = Caster::PREFIX_VIRTUAL;
$mode = $c->getIteratorMode();
$c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE);
$a += array(
$prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_KEEP) ? 'IT_MODE_KEEP' : 'IT_MODE_DELETE'), $mode),
$prefix.'dllist' => iterator_to_array($c),
);
$c->setIteratorMode($mode);
$a += array(
$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;
}
return $a;
}
public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested)
{
static $map = array(
'path' => 'getPath',
'filename' => 'getFilename',
'basename' => 'getBasename',
'pathname' => 'getPathname',
'extension' => 'getExtension',
'realPath' => 'getRealPath',
'aTime' => 'getATime',
'mTime' => 'getMTime',
'cTime' => 'getCTime',
'inode' => 'getInode',
'size' => 'getSize',
'perms' => 'getPerms',
'owner' => 'getOwner',
'group' => 'getGroup',
'type' => 'getType',
'writable' => 'isWritable',
'readable' => 'isReadable',
'executable' => 'isExecutable',
'file' => 'isFile',
'dir' => 'isDir',
'link' => 'isLink',
'linkTarget' => 'getLinkTarget',
);
public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, $isNested)
{
static $map = array(
'path' => 'getPath',
'filename' => 'getFilename',
'basename' => 'getBasename',
'pathname' => 'getPathname',
'extension' => 'getExtension',
'realPath' => 'getRealPath',
'aTime' => 'getATime',
'mTime' => 'getMTime',
'cTime' => 'getCTime',
'inode' => 'getInode',
'size' => 'getSize',
'perms' => 'getPerms',
'owner' => 'getOwner',
'group' => 'getGroup',
'type' => 'getType',
'writable' => 'isWritable',
'readable' => 'isReadable',
'executable' => 'isExecutable',
'file' => 'isFile',
'dir' => 'isDir',
'link' => 'isLink',
'linkTarget' => 'getLinkTarget',
);
$prefix = Caster::PREFIX_VIRTUAL;
$prefix = Caster::PREFIX_VIRTUAL;
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
if (isset($a[$prefix.'perms'])) {
$a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
}
if (isset($a[$prefix.'realPath'])) {
$a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']);
}
static $mapDate = array('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]);
}
}
if (isset($a[$prefix.'perms'])) {
$a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']);
}
return $a;
}
static $mapDate = array('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]);
}
}
public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested)
{
static $map = array(
'csvControl' => 'getCsvControl',
'flags' => 'getFlags',
'maxLineLen' => 'getMaxLineLen',
'fstat' => 'fstat',
'eof' => 'eof',
'key' => 'key',
);
return $a;
}
$prefix = Caster::PREFIX_VIRTUAL;
public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, $isNested)
{
static $map = array(
'csvControl' => 'getCsvControl',
'flags' => 'getFlags',
'maxLineLen' => 'getMaxLineLen',
'fstat' => 'fstat',
'eof' => 'eof',
'key' => 'key',
);
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
$prefix = Caster::PREFIX_VIRTUAL;
if (isset($a[$prefix.'flags'])) {
$flagsArray = array();
foreach (self::$splFileObjectFlags as $value => $name) {
if ($a[$prefix.'flags'] & $value) {
$flagsArray[] = $name;
}
}
$a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']);
}
foreach ($map as $key => $accessor) {
try {
$a[$prefix.$key] = $c->$accessor();
} catch (\Exception $e) {
}
}
if (isset($a[$prefix.'fstat'])) {
$a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], array('dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks'));
}
if (isset($a[$prefix.'flags'])) {
$flagsArray = array();
foreach (self::$splFileObjectFlags as $value => $name) {
if ($a[$prefix.'flags'] & $value) {
$flagsArray[] = $name;
}
}
$a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']);
}
return $a;
}
if (isset($a[$prefix.'fstat'])) {
$a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], array('dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks'));
}
public static function castFixedArray(\SplFixedArray $c, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'storage' => $c->toArray(),
);
return $a;
}
return $a;
}
public static function castFixedArray(\SplFixedArray $c, array $a, Stub $stub, $isNested)
{
$a += array(
Caster::PREFIX_VIRTUAL.'storage' => $c->toArray(),
);
public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested)
{
$storage = array();
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
return $a;
}
foreach ($c as $obj) {
$storage[spl_object_hash($obj)] = array(
'object' => $obj,
'info' => $c->getInfo(),
);
}
public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, $isNested)
{
$storage = array();
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
$a += array(
Caster::PREFIX_VIRTUAL.'storage' => $storage,
);
foreach (clone $c as $obj) {
$storage[spl_object_hash($obj)] = array(
'object' => $obj,
'info' => $c->getInfo(),
);
}
return $a;
}
$a += array(
Caster::PREFIX_VIRTUAL.'storage' => $storage,
);
public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator();
return $a;
}
return $a;
}
public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, $isNested)
{
$a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator();
return $a;
}
}

View File

@ -20,53 +20,63 @@ use Symfony\Component\VarDumper\Cloner\Stub;
*/
class StubCaster
{
public static function castStub(Stub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->type = $c->type;
$stub->class = $c->class;
$stub->value = $c->value;
$stub->handle = $c->handle;
$stub->cut = $c->cut;
public static function castStub(Stub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->type = $c->type;
$stub->class = $c->class;
$stub->value = $c->value;
$stub->handle = $c->handle;
$stub->cut = $c->cut;
$stub->attr = $c->attr;
return array();
}
}
if (Stub::TYPE_REF === $c->type && !$c->class && is_string($c->value) && !preg_match('//u', $c->value)) {
$stub->type = Stub::TYPE_STRING;
$stub->class = Stub::STRING_BINARY;
}
public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested)
{
return $isNested ? $c->preservedSubset : $a;
}
$a = array();
}
public static function cutInternals($obj, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->cut += count($a);
return $a;
}
return array();
}
public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, $isNested)
{
return $isNested ? $c->preservedSubset : $a;
}
return $a;
}
public static function cutInternals($obj, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->cut += count($a);
public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->class = '';
$stub->handle = 0;
$stub->value = null;
return array();
}
$a = array();
return $a;
}
if ($c->value) {
foreach (array_keys($c->value) as $k) {
$keys[] = Caster::PREFIX_VIRTUAL.$k;
}
// Preserve references with array_combine()
$a = array_combine($keys, $c->value);
}
}
public static function castEnum(EnumStub $c, array $a, Stub $stub, $isNested)
{
if ($isNested) {
$stub->class = $c->dumpKeys ? '' : null;
$stub->handle = 0;
$stub->value = null;
$stub->cut = $c->cut;
$stub->attr = $c->attr;
return $a;
}
$a = array();
if ($c->value) {
foreach (array_keys($c->value) as $k) {
$keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k;
}
// Preserve references with array_combine()
$a = array_combine($keys, $c->value);
}
}
return $a;
}
}

View File

@ -0,0 +1,77 @@
<?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;
/**
* Casts XmlReader class to array representation.
*
* @author Baptiste Clavié <clavie.b@gmail.com>
*/
class XmlReaderCaster
{
private static $nodeTypes = array(
\XmlReader::NONE => 'NONE',
\XmlReader::ELEMENT => 'ELEMENT',
\XmlReader::ATTRIBUTE => 'ATTRIBUTE',
\XmlReader::TEXT => 'TEXT',
\XmlReader::CDATA => 'CDATA',
\XmlReader::ENTITY_REF => 'ENTITY_REF',
\XmlReader::ENTITY => 'ENTITY',
\XmlReader::PI => 'PI (Processing Instruction)',
\XmlReader::COMMENT => 'COMMENT',
\XmlReader::DOC => 'DOC',
\XmlReader::DOC_TYPE => 'DOC_TYPE',
\XmlReader::DOC_FRAGMENT => 'DOC_FRAGMENT',
\XmlReader::NOTATION => 'NOTATION',
\XmlReader::WHITESPACE => 'WHITESPACE',
\XmlReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE',
\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)
{
$props = Caster::PREFIX_VIRTUAL.'parserProperties';
$info = array(
'localName' => $reader->localName,
'prefix' => $reader->prefix,
'nodeType' => new ConstStub(self::$nodeTypes[$reader->nodeType], $reader->nodeType),
'depth' => $reader->depth,
'isDefault' => $reader->isDefault,
'isEmptyElement' => \XmlReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement,
'xmlLang' => $reader->xmlLang,
'attributeCount' => $reader->attributeCount,
'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),
),
);
if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, array(), $count)) {
$info[$props] = new EnumStub($info[$props]);
$info[$props]->cut = $count;
}
$info = Caster::filter($info, Caster::EXCLUDE_EMPTY, array(), $count);
// +2 because hasValue and hasAttributes are always filtered
$stub->cut += $count + 2;
return $a + $info;
}
}

View File

@ -21,293 +21,302 @@ use Symfony\Component\VarDumper\Exception\ThrowingCasterException;
*/
abstract class AbstractCloner implements ClonerInterface
{
public static $defaultCasters = array(
'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',
public static $defaultCasters = array(
'__PHP_Incomplete_Class' => 'Symfony\Component\VarDumper\Caster\Caster::castPhpIncompleteClass',
'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',
'ReflectionExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castExtension',
'ReflectionZendExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castZendExtension',
'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',
'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',
'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',
'ReflectionExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castExtension',
'ReflectionZendExtension' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castZendExtension',
'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',
'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',
'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\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',
'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',
'PHPUnit_Framework_MockObject_MockObject' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'Prophecy\Prophecy\ProphecySubjectInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'Mockery\MockInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'XmlReader' => 'Symfony\Component\VarDumper\Caster\XmlReaderCaster::castXmlReader',
'PDO' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdo',
'PDOStatement' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdoStatement',
'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\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',
'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',
'PHPUnit_Framework_MockObject_MockObject' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'Prophecy\Prophecy\ProphecySubjectInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'Mockery\MockInterface' => 'Symfony\Component\VarDumper\Caster\StubCaster::cutInternals',
'ArrayObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castArrayObject',
'SplDoublyLinkedList' => 'Symfony\Component\VarDumper\Caster\SplCaster::castDoublyLinkedList',
'SplFileInfo' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileInfo',
'SplFileObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileObject',
'SplFixedArray' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFixedArray',
'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',
'PDO' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdo',
'PDOStatement' => 'Symfony\Component\VarDumper\Caster\PdoCaster::castPdoStatement',
'MongoCursorInterface' => 'Symfony\Component\VarDumper\Caster\MongoCaster::castCursor',
'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',
':curl' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castCurl',
':dba' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba',
':dba persistent' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba',
':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',
':stream-context' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStreamContext',
':xml' => 'Symfony\Component\VarDumper\Caster\XmlResourceCaster::castXml',
);
'ArrayObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castArrayObject',
'SplDoublyLinkedList' => 'Symfony\Component\VarDumper\Caster\SplCaster::castDoublyLinkedList',
'SplFileInfo' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileInfo',
'SplFileObject' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFileObject',
'SplFixedArray' => 'Symfony\Component\VarDumper\Caster\SplCaster::castFixedArray',
'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',
protected $maxItems = 2500;
protected $maxString = -1;
protected $useExt;
'MongoCursorInterface' => 'Symfony\Component\VarDumper\Caster\MongoCaster::castCursor',
private $casters = array();
private $prevErrorHandler;
private $classInfo = array();
private $filter = 0;
'Redis' => 'Symfony\Component\VarDumper\Caster\RedisCaster::castRedis',
'RedisArray' => 'Symfony\Component\VarDumper\Caster\RedisCaster::castRedisArray',
/**
* @param callable[]|null $casters A map of casters.
*
* @see addCasters
*/
public function __construct(array $casters = null)
{
if (null === $casters) {
$casters = static::$defaultCasters;
}
$this->addCasters($casters);
$this->useExt = extension_loaded('symfony_debug');
}
':curl' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castCurl',
':dba' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba',
':dba persistent' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba',
':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',
':persistent stream' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStream',
':stream-context' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStreamContext',
':xml' => 'Symfony\Component\VarDumper\Caster\XmlResourceCaster::castXml',
);
/**
* Adds casters for resources and objects.
*
* Maps resources or objects types to a callback.
* Types are in the key, with a callable caster for value.
* Resource types are to be prefixed with a `:`,
* see e.g. static::$defaultCasters.
*
* @param callable[] $casters A map of casters.
*/
public function addCasters(array $casters)
{
foreach ($casters as $type => $callback) {
$this->casters[strtolower($type)][] = $callback;
}
}
protected $maxItems = 2500;
protected $maxString = -1;
protected $useExt;
/**
* Sets the maximum number of items to clone past the first level in nested structures.
*
* @param int $maxItems
*/
public function setMaxItems($maxItems)
{
$this->maxItems = (int) $maxItems;
}
private $casters = array();
private $prevErrorHandler;
private $classInfo = array();
private $filter = 0;
/**
* Sets the maximum cloned length for strings.
*
* @param int $maxString
*/
public function setMaxString($maxString)
{
$this->maxString = (int) $maxString;
}
/**
* @param callable[]|null $casters A map of casters
*
* @see addCasters
*/
public function __construct(array $casters = null)
{
if (null === $casters) {
$casters = static::$defaultCasters;
}
$this->addCasters($casters);
$this->useExt = extension_loaded('symfony_debug');
}
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable.
* @param int $filter A bit field of Caster::EXCLUDE_* constants.
*
* @return Data The cloned variable represented by a Data object.
*/
public function cloneVar($var, $filter = 0)
{
$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);
}
/**
* Adds casters for resources and objects.
*
* Maps resources or objects types to a callback.
* Types are in the key, with a callable caster for value.
* Resource types are to be prefixed with a `:`,
* see e.g. static::$defaultCasters.
*
* @param callable[] $casters A map of casters
*/
public function addCasters(array $casters)
{
foreach ($casters as $type => $callback) {
$this->casters[strtolower($type)][] = $callback;
}
}
if ($this->prevErrorHandler) {
return call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context);
}
/**
* Sets the maximum number of items to clone past the first level in nested structures.
*
* @param int $maxItems
*/
public function setMaxItems($maxItems)
{
$this->maxItems = (int) $maxItems;
}
return false;
});
$this->filter = $filter;
/**
* Sets the maximum cloned length for strings.
*
* @param int $maxString
*/
public function setMaxString($maxString)
{
$this->maxString = (int) $maxString;
}
try {
$data = $this->doClone($var);
} catch (\Exception $e) {
}
restore_error_handler();
$this->prevErrorHandler = null;
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable
* @param int $filter A bit field of Caster::EXCLUDE_* constants
*
* @return Data The cloned variable represented by a Data object
*/
public function cloneVar($var, $filter = 0)
{
$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 (isset($e)) {
throw $e;
}
if ($this->prevErrorHandler) {
return call_user_func($this->prevErrorHandler, $type, $msg, $file, $line, $context);
}
return new Data($data);
}
return false;
});
$this->filter = $filter;
/**
* Effectively clones the PHP variable.
*
* @param mixed $var Any PHP variable.
*
* @return array The cloned variable represented in an array.
*/
abstract protected function doClone($var);
try {
$data = $this->doClone($var);
} catch (\Exception $e) {
}
restore_error_handler();
$this->prevErrorHandler = null;
/**
* 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.
*/
protected function castObject(Stub $stub, $isNested)
{
$obj = $stub->value;
$class = $stub->class;
if (isset($e)) {
throw $e;
}
if (isset($class[15]) && "\0" === $class[15] && 0 === strpos($class, "class@anonymous\x00")) {
$stub->class = get_parent_class($class).'@anonymous';
}
if (isset($this->classInfo[$class])) {
$classInfo = $this->classInfo[$class];
} else {
$classInfo = array(
new \ReflectionClass($class),
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
);
return new Data($data);
}
$this->classInfo[$class] = $classInfo;
}
/**
* Effectively clones the PHP variable.
*
* @param mixed $var Any PHP variable
*
* @return array The cloned variable represented in an array
*/
abstract protected function doClone($var);
$a = $this->callCaster('Symfony\Component\VarDumper\Caster\Caster::castObject', $obj, $classInfo[0], null, $isNested);
/**
* 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
*/
protected function castObject(Stub $stub, $isNested)
{
$obj = $stub->value;
$class = $stub->class;
foreach ($classInfo[1] as $p) {
if (!empty($this->casters[$p = strtolower($p)])) {
foreach ($this->casters[$p] as $p) {
$a = $this->callCaster($p, $obj, $a, $stub, $isNested);
}
}
}
if (isset($class[15]) && "\0" === $class[15] && 0 === strpos($class, "class@anonymous\x00")) {
$stub->class = get_parent_class($class).'@anonymous';
}
if (isset($this->classInfo[$class])) {
$classInfo = $this->classInfo[$class];
} else {
$classInfo = array(
new \ReflectionClass($class),
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
);
$classInfo[1] = array_map('strtolower', $classInfo[1]);
return $a;
}
$this->classInfo[$class] = $classInfo;
}
/**
* 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();
$res = $stub->value;
$type = $stub->class;
$a = Caster::castObject($obj, $classInfo[0]);
if (!empty($this->casters[':'.$type])) {
foreach ($this->casters[':'.$type] as $c) {
$a = $this->callCaster($c, $res, $a, $stub, $isNested);
}
}
foreach ($classInfo[1] as $p) {
if (!empty($this->casters[$p])) {
foreach ($this->casters[$p] as $p) {
$a = $this->callCaster($p, $obj, $a, $stub, $isNested);
}
}
}
return $a;
}
return $a;
}
/**
* Calls a custom caster.
*
* @param callable $callback The caster.
* @param object|resource $obj The object/resource being casted.
* @param array $a The result of the previous cast for chained casters.
* @param Stub $stub The Stub for the casted object/resource.
* @param bool $isNested True if $obj is nested in the dumped structure.
*
* @return array The casted object/resource.
*/
private function callCaster($callback, $obj, $a, $stub, $isNested)
{
try {
$cast = call_user_func($callback, $obj, $a, $stub, $isNested, $this->filter);
/**
* 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();
$res = $stub->value;
$type = $stub->class;
if (is_array($cast)) {
$a = $cast;
}
} catch (\Exception $e) {
$a[(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠'] = new ThrowingCasterException($e);
}
if (!empty($this->casters[':'.$type])) {
foreach ($this->casters[':'.$type] as $c) {
$a = $this->callCaster($c, $res, $a, $stub, $isNested);
}
}
return $a;
}
return $a;
}
/**
* Calls a custom caster.
*
* @param callable $callback The caster
* @param object|resource $obj The object/resource being casted
* @param array $a The result of the previous cast for chained casters
* @param Stub $stub The Stub for the casted object/resource
* @param bool $isNested True if $obj is nested in the dumped structure
*
* @return array The casted object/resource
*/
private function callCaster($callback, $obj, $a, $stub, $isNested)
{
try {
$cast = call_user_func($callback, $obj, $a, $stub, $isNested, $this->filter);
if (is_array($cast)) {
$a = $cast;
}
} catch (\Exception $e) {
$a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a;
}
return $a;
}
}

View File

@ -16,12 +16,12 @@ namespace Symfony\Component\VarDumper\Cloner;
*/
interface ClonerInterface
{
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable.
*
* @return Data The cloned variable represented by a Data object.
*/
public function cloneVar($var);
/**
* Clones a PHP variable.
*
* @param mixed $var Any PHP variable
*
* @return Data The cloned variable represented by a Data object
*/
public function cloneVar($var);
}

View File

@ -18,24 +18,25 @@ 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;
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 $depth = 0;
public $refIndex = 0;
public $softRefTo = 0;
public $softRefCount = 0;
public $softRefHandle = 0;
public $hardRefTo = 0;
public $hardRefCount = 0;
public $hardRefHandle = 0;
public $hashType;
public $hashKey;
public $hashKeyIsBinary;
public $hashIndex = 0;
public $hashLength = 0;
public $hashCut = 0;
public $stop = false;
public $depth = 0;
public $refIndex = 0;
public $softRefTo = 0;
public $softRefCount = 0;
public $softRefHandle = 0;
public $hardRefTo = 0;
public $hardRefCount = 0;
public $hardRefHandle = 0;
public $hashType;
public $hashKey;
public $hashKeyIsBinary;
public $hashIndex = 0;
public $hashLength = 0;
public $hashCut = 0;
public $stop = false;
public $attr = array();
}

View File

@ -11,208 +11,260 @@
namespace Symfony\Component\VarDumper\Cloner;
use Symfony\Component\VarDumper\Caster\Caster;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class Data
{
private $data;
private $maxDepth = 20;
private $maxItemsPerDepth = -1;
private $useRefHandles = -1;
private $data;
private $position = 0;
private $key = 0;
private $maxDepth = 20;
private $maxItemsPerDepth = -1;
private $useRefHandles = -1;
/**
* @param array $data A array as returned by ClonerInterface::cloneVar().
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* @param array $data A array as returned by ClonerInterface::cloneVar()
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* @return array The raw data structure.
*/
public function getRawData()
{
return $this->data;
}
/**
* @return array The raw data structure
*/
public function getRawData()
{
return $this->data;
}
/**
* Returns a depth limited clone of $this.
*
* @param int $maxDepth The max dumped depth level.
*
* @return self A clone of $this.
*/
public function withMaxDepth($maxDepth)
{
$data = clone $this;
$data->maxDepth = (int) $maxDepth;
/**
* Returns a depth limited clone of $this.
*
* @param int $maxDepth The max dumped depth level
*
* @return self A clone of $this
*/
public function withMaxDepth($maxDepth)
{
$data = clone $this;
$data->maxDepth = (int) $maxDepth;
return $data;
}
return $data;
}
/**
* Limits the numbers of elements per depth level.
*
* @param int $maxItemsPerDepth The max number of items dumped per depth level.
*
* @return self A clone of $this.
*/
public function withMaxItemsPerDepth($maxItemsPerDepth)
{
$data = clone $this;
$data->maxItemsPerDepth = (int) $maxItemsPerDepth;
/**
* Limits the number of elements per depth level.
*
* @param int $maxItemsPerDepth The max number of items dumped per depth level
*
* @return self A clone of $this
*/
public function withMaxItemsPerDepth($maxItemsPerDepth)
{
$data = clone $this;
$data->maxItemsPerDepth = (int) $maxItemsPerDepth;
return $data;
}
return $data;
}
/**
* Enables/disables objects' identifiers tracking.
*
* @param bool $useRefHandles False to hide global ref. handles.
*
* @return self A clone of $this.
*/
public function withRefHandles($useRefHandles)
{
$data = clone $this;
$data->useRefHandles = $useRefHandles ? -1 : 0;
/**
* Enables/disables objects' identifiers tracking.
*
* @param bool $useRefHandles False to hide global ref. handles
*
* @return self A clone of $this
*/
public function withRefHandles($useRefHandles)
{
$data = clone $this;
$data->useRefHandles = $useRefHandles ? -1 : 0;
return $data;
}
return $data;
}
/**
* Dumps data with a DumperInterface dumper.
*/
public function dump(DumperInterface $dumper)
{
$refs = array(0);
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[0][0]);
}
/**
* 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 of null if the key is not set
*/
public function seek($key)
{
$item = $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.
*/
private function dumpItem($dumper, $cursor, &$refs, $item)
{
$cursor->refIndex = 0;
$cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
$cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
$firstSeen = true;
if (!$item instanceof Stub || !$item->position) {
return;
}
$keys = array($key);
if (!$item instanceof Stub) {
$type = gettype($item);
} elseif (Stub::TYPE_REF === $item->type) {
if ($item->handle) {
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;
}
$type = $item->class ?: gettype($item->value);
$item = $item->value;
}
if ($item instanceof Stub) {
if ($item->refCount) {
if (!isset($refs[$r = $item->handle])) {
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
} else {
$firstSeen = false;
}
$cursor->softRefTo = $refs[$r];
}
$cursor->softRefHandle = $this->useRefHandles & $item->handle;
$cursor->softRefCount = $item->refCount;
$cut = $item->cut;
switch ($item->type) {
case Stub::TYPE_OBJECT:
$keys[] = Caster::PREFIX_DYNAMIC.$key;
$keys[] = Caster::PREFIX_PROTECTED.$key;
$keys[] = Caster::PREFIX_VIRTUAL.$key;
$keys[] = "\0$item->class\0$key";
case Stub::TYPE_ARRAY:
case Stub::TYPE_RESOURCE:
break;
default:
return;
}
if ($item->position && $firstSeen) {
$children = $this->data[$item->position];
$data = null;
$children = $this->data[$item->position];
if ($cursor->stop) {
if ($cut >= 0) {
$cut += count($children);
}
$children = array();
}
} else {
$children = array();
}
switch ($item->type) {
case Stub::TYPE_STRING:
$dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
break;
foreach ($keys as $key) {
if (isset($children[$key]) || array_key_exists($key, $children)) {
$data = clone $this;
$data->key = $key;
$data->position = $item->position;
break;
}
}
case Stub::TYPE_ARRAY:
$item = clone $item;
$item->type = $item->class;
$item->class = $item->value;
// No break;
case Stub::TYPE_OBJECT:
case Stub::TYPE_RESOURCE:
$withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
$dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
if ($withChildren) {
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type);
} elseif ($children && 0 <= $cut) {
$cut += count($children);
}
$dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
break;
return $data;
}
default:
throw new \RuntimeException(sprintf('Unexpected Stub type: %s', $item->type));
}
} elseif ('array' === $type) {
$dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
$dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
} elseif ('string' === $type) {
$dumper->dumpString($cursor, $item, false, 0);
} else {
$dumper->dumpScalar($cursor, $type, $item);
}
}
/**
* Dumps data with a DumperInterface dumper.
*/
public function dump(DumperInterface $dumper)
{
$refs = array(0);
$this->dumpItem($dumper, new Cursor(), $refs, $this->data[$this->position][$this->key]);
}
/**
* 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.
*
* @return int The final number of removed items.
*/
private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCut, $hashType)
{
$cursor = clone $parentCursor;
++$cursor->depth;
$cursor->hashType = $hashType;
$cursor->hashIndex = 0;
$cursor->hashLength = count($children);
$cursor->hashCut = $hashCut;
foreach ($children as $key => $child) {
$cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key);
$cursor->hashKey = $key;
$this->dumpItem($dumper, $cursor, $refs, $child);
if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
$parentCursor->stop = true;
/**
* 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
*/
private function dumpItem($dumper, $cursor, &$refs, $item)
{
$cursor->refIndex = 0;
$cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0;
$cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0;
$firstSeen = true;
return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
}
}
if (!$item instanceof Stub) {
$cursor->attr = array();
$type = gettype($item);
} elseif (Stub::TYPE_REF === $item->type) {
if ($item->handle) {
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->attr = $item->attr;
$type = $item->class ?: gettype($item->value);
$item = $item->value;
}
if ($item instanceof Stub) {
if ($item->refCount) {
if (!isset($refs[$r = $item->handle])) {
$cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0];
} else {
$firstSeen = false;
}
$cursor->softRefTo = $refs[$r];
}
$cursor->softRefHandle = $this->useRefHandles & $item->handle;
$cursor->softRefCount = $item->refCount;
$cursor->attr = $item->attr;
$cut = $item->cut;
return $hashCut;
}
if ($item->position && $firstSeen) {
$children = $this->data[$item->position];
if ($cursor->stop) {
if ($cut >= 0) {
$cut += count($children);
}
$children = array();
}
} else {
$children = array();
}
switch ($item->type) {
case Stub::TYPE_STRING:
$dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut);
break;
case Stub::TYPE_ARRAY:
$item = clone $item;
$item->type = $item->class;
$item->class = $item->value;
// No break;
case Stub::TYPE_OBJECT:
case Stub::TYPE_RESOURCE:
$withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth;
$dumper->enterHash($cursor, $item->type, $item->class, $withChildren);
if ($withChildren) {
$cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class);
} elseif ($children && 0 <= $cut) {
$cut += count($children);
}
$dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut);
break;
default:
throw new \RuntimeException(sprintf('Unexpected Stub type: %s', $item->type));
}
} elseif ('array' === $type) {
$dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false);
$dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0);
} elseif ('string' === $type) {
$dumper->dumpString($cursor, $item, false, 0);
} else {
$dumper->dumpScalar($cursor, $type, $item);
}
}
/**
* 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)
{
$cursor = clone $parentCursor;
++$cursor->depth;
$cursor->hashType = $hashType;
$cursor->hashIndex = 0;
$cursor->hashLength = count($children);
$cursor->hashCut = $hashCut;
foreach ($children as $key => $child) {
$cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key);
$cursor->hashKey = $dumpKeys ? $key : null;
$this->dumpItem($dumper, $cursor, $refs, $child);
if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) {
$parentCursor->stop = true;
return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut;
}
}
return $hashCut;
}
}

View File

@ -18,43 +18,43 @@ namespace Symfony\Component\VarDumper\Cloner;
*/
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 scalar $value The scalar value being dumped.
*/
public function dumpScalar(Cursor $cursor, $type, $value);
/**
* 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 scalar $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.
*/
public function dumpString(Cursor $cursor, $str, $bin, $cut);
/**
* 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
*/
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.
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild);
/**
* 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
*/
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.
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
/**
* 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
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut);
}

View File

@ -18,23 +18,24 @@ namespace Symfony\Component\VarDumper\Cloner;
*/
class Stub
{
const TYPE_REF = 'ref';
const TYPE_STRING = 'string';
const TYPE_ARRAY = 'array';
const TYPE_OBJECT = 'object';
const TYPE_RESOURCE = 'resource';
const TYPE_REF = 'ref';
const TYPE_STRING = 'string';
const TYPE_ARRAY = 'array';
const TYPE_OBJECT = 'object';
const TYPE_RESOURCE = 'resource';
const STRING_BINARY = 'bin';
const STRING_UTF8 = 'utf8';
const STRING_BINARY = 'bin';
const STRING_UTF8 = 'utf8';
const ARRAY_ASSOC = 'assoc';
const ARRAY_INDEXED = 'indexed';
const ARRAY_ASSOC = 'assoc';
const ARRAY_INDEXED = 'indexed';
public $type = self::TYPE_REF;
public $class = '';
public $value;
public $cut = 0;
public $handle = 0;
public $refCount = 0;
public $position = 0;
public $type = self::TYPE_REF;
public $class = '';
public $value;
public $cut = 0;
public $handle = 0;
public $refCount = 0;
public $position = 0;
public $attr = array();
}

View File

@ -16,285 +16,311 @@ namespace Symfony\Component\VarDumper\Cloner;
*/
class VarCloner extends AbstractCloner
{
private static $hashMask = 0;
private static $hashOffset = 0;
private static $hashMask = 0;
private static $hashOffset = 0;
/**
* {@inheritdoc}
*/
protected function doClone($var)
{
$useExt = $this->useExt;
$i = 0; // Current iteration position in $queue
$len = 1; // Length of $queue
$pos = 0; // Number of cloned items past the first level
$refs = 0; // Hard references counter
$queue = array(array($var)); // This breadth-first queue is the return value
$arrayRefs = array(); // Map of queue indexes to stub array objects
$hardRefs = array(); // Map of original zval hashes to stub objects
$objRefs = array(); // Map of original object handles to their stub object couterpart
$resRefs = array(); // Map of original resource handles to their stub object couterpart
$values = array(); // Map of stub objects' hashes to original values
$maxItems = $this->maxItems;
$maxString = $this->maxString;
$cookie = (object) array(); // Unique object used to detect hard references
$gid = uniqid(mt_rand(), true); // Unique string used to detect the special $GLOBALS variable
$a = null; // Array cast for nested structures
$stub = null; // Stub capturing the main properties of an original item value
// or null if the original value is used directly
$zval = array( // Main properties of the current value
'type' => null,
'zval_isref' => null,
'zval_hash' => null,
'array_count' => null,
'object_class' => null,
'object_handle' => null,
'resource_type' => null,
);
if (!self::$hashMask) {
self::initHashMask();
}
$hashMask = self::$hashMask;
$hashOffset = self::$hashOffset;
/**
* {@inheritdoc}
*/
protected function doClone($var)
{
$useExt = $this->useExt;
$len = 1; // Length of $queue
$pos = 0; // Number of cloned items past the first level
$refsCounter = 0; // Hard references counter
$queue = array(array($var)); // This breadth-first queue is the return value
$arrayRefs = array(); // Map of queue indexes to stub array objects
$hardRefs = array(); // Map of original zval hashes to stub objects
$objRefs = array(); // Map of original object handles to their stub object couterpart
$resRefs = array(); // Map of original resource handles to their stub object couterpart
$values = array(); // Map of stub objects' hashes to original values
$maxItems = $this->maxItems;
$maxString = $this->maxString;
$cookie = (object) array(); // Unique object used to detect hard references
$gid = uniqid(mt_rand(), true); // Unique string used to detect the special $GLOBALS variable
$a = null; // Array cast for nested structures
$stub = null; // Stub capturing the main properties of an original item value
// or null if the original value is used directly
$zval = array( // Main properties of the current value
'type' => null,
'zval_isref' => null,
'zval_hash' => null,
'array_count' => null,
'object_class' => null,
'object_handle' => null,
'resource_type' => null,
);
if (!self::$hashMask) {
self::initHashMask();
}
$hashMask = self::$hashMask;
$hashOffset = self::$hashOffset;
for ($i = 0; $i < $len; ++$i) {
$indexed = true; // Whether the currently iterated array is numerically indexed or not
$j = -1; // Position in the currently iterated array
$step = $queue[$i]; // Copy of the currently iterated array used for hard references detection
foreach ($step as $k => $v) {
// $k is the original key
// $v is the original value or a stub object in case of hard references
if ($indexed && $k !== ++$j) {
$indexed = false;
}
if ($useExt) {
$zval = symfony_zval_info($k, $step);
} else {
$step[$k] = $cookie;
if ($zval['zval_isref'] = $queue[$i][$k] === $cookie) {
$zval['zval_hash'] = $v instanceof Stub ? spl_object_hash($v) : null;
}
$zval['type'] = gettype($v);
}
if ($zval['zval_isref']) {
$queue[$i][$k] = &$stub; // Break hard references to make $queue completely
unset($stub); // independent from the original structure
if (isset($hardRefs[$zval['zval_hash']])) {
$queue[$i][$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($step[$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;
}
}
// Create $stub when the original value $v can not be used directly
// If $v is a nested structure, put that structure in array $a
switch ($zval['type']) {
case 'string':
if (isset($v[0]) && !preg_match('//u', $v)) {
$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);
} else {
$stub->value = $v;
}
} elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = iconv_strlen($v, 'UTF-8') - $maxString) {
$stub = new Stub();
$stub->type = Stub::TYPE_STRING;
$stub->class = Stub::STRING_UTF8;
$stub->cut = $cut;
$stub->value = iconv_substr($v, 0, $maxString, 'UTF-8');
}
break;
for ($i = 0; $i < $len; ++$i) {
$indexed = true; // Whether the currently iterated array is numerically indexed or not
$j = -1; // Position in the currently iterated array
$fromObjCast = array_keys($queue[$i]);
$fromObjCast = array_keys(array_flip($fromObjCast)) !== $fromObjCast;
$refs = $vals = $fromObjCast ? array_values($queue[$i]) : $queue[$i];
foreach ($queue[$i] as $k => $v) {
// $k is the original key
// $v is the original value or a stub object in case of hard references
if ($k !== ++$j) {
$indexed = false;
}
if ($fromObjCast) {
$k = $j;
}
if ($useExt) {
$zval = symfony_zval_info($k, $refs);
} else {
$refs[$k] = $cookie;
if ($zval['zval_isref'] = $vals[$k] === $cookie) {
$zval['zval_hash'] = $v instanceof Stub ? spl_object_hash($v) : null;
}
$zval['type'] = gettype($v);
}
if ($zval['zval_isref']) {
$vals[$k] = &$stub; // Break hard references to make $queue completely
unset($stub); // independent from the original structure
if (isset($hardRefs[$zval['zval_hash']])) {
$vals[$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($refs[$k] = $v);
if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) {
++$v->value->refCount;
}
++$v->refCount;
continue;
}
}
// Create $stub when the original value $v can not be used directly
// If $v is a nested structure, put that structure in array $a
switch ($zval['type']) {
case 'string':
if (isset($v[0]) && !preg_match('//u', $v)) {
$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);
} else {
$stub->value = $v;
}
} 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');
}
break;
case 'integer':
break;
case 'integer':
break;
case 'array':
if ($v) {
$stub = $arrayRefs[$len] = new Stub();
$stub->type = Stub::TYPE_ARRAY;
$stub->class = Stub::ARRAY_ASSOC;
case 'array':
if ($v) {
$stub = $arrayRefs[$len] = new Stub();
$stub->type = Stub::TYPE_ARRAY;
$stub->class = Stub::ARRAY_ASSOC;
// Copies of $GLOBALS have very strange behavior,
// let's detect them with some black magic
$a = $v;
$a[$gid] = true;
// Copies of $GLOBALS have very strange behavior,
// let's detect them with some black magic
$a = $v;
$a[$gid] = true;
// Happens with copies of $GLOBALS
if (isset($v[$gid])) {
unset($v[$gid]);
$a = array();
foreach ($v as $gk => &$gv) {
$a[$gk] = &$gv;
}
} else {
$a = $v;
}
// Happens with copies of $GLOBALS
if (isset($v[$gid])) {
unset($v[$gid]);
$a = array();
foreach ($v as $gk => &$gv) {
$a[$gk] = &$gv;
}
} else {
$a = $v;
}
$stub->value = $zval['array_count'] ?: count($a);
}
break;
$stub->value = $zval['array_count'] ?: count($a);
}
break;
case 'object':
if (empty($objRefs[$h = $zval['object_handle'] ?: ($hashMask ^ hexdec(substr(spl_object_hash($v), $hashOffset, PHP_INT_SIZE)))])) {
$stub = new Stub();
$stub->type = Stub::TYPE_OBJECT;
$stub->class = $zval['object_class'] ?: get_class($v);
$stub->value = $v;
$stub->handle = $h;
$a = $this->castObject($stub, 0 < $i);
if ($v !== $stub->value) {
if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
break;
}
if ($useExt) {
$zval['type'] = $stub->value;
$zval = symfony_zval_info('type', $zval);
$h = $zval['object_handle'];
} else {
$h = $hashMask ^ hexdec(substr(spl_object_hash($stub->value), $hashOffset, PHP_INT_SIZE));
}
$stub->handle = $h;
}
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos) {
$stub->cut = count($a);
$a = null;
}
}
if (empty($objRefs[$h])) {
$objRefs[$h] = $stub;
} else {
$stub = $objRefs[$h];
++$stub->refCount;
$a = null;
}
break;
case 'object':
if (empty($objRefs[$h = $zval['object_handle'] ?: ($hashMask ^ hexdec(substr(spl_object_hash($v), $hashOffset, PHP_INT_SIZE)))])) {
$stub = new Stub();
$stub->type = Stub::TYPE_OBJECT;
$stub->class = $zval['object_class'] ?: get_class($v);
$stub->value = $v;
$stub->handle = $h;
$a = $this->castObject($stub, 0 < $i);
if ($v !== $stub->value) {
if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) {
break;
}
if ($useExt) {
$zval['type'] = $stub->value;
$zval = symfony_zval_info('type', $zval);
$h = $zval['object_handle'];
} else {
$h = $hashMask ^ hexdec(substr(spl_object_hash($stub->value), $hashOffset, PHP_INT_SIZE));
}
$stub->handle = $h;
}
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos) {
$stub->cut = count($a);
$a = null;
}
}
if (empty($objRefs[$h])) {
$objRefs[$h] = $stub;
} else {
$stub = $objRefs[$h];
++$stub->refCount;
$a = null;
}
break;
case 'resource':
case 'unknown type':
if (empty($resRefs[$h = (int) $v])) {
$stub = new Stub();
$stub->type = Stub::TYPE_RESOURCE;
$stub->class = $zval['resource_type'] ?: get_resource_type($v);
$stub->value = $v;
$stub->handle = $h;
$a = $this->castResource($stub, 0 < $i);
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos) {
$stub->cut = count($a);
$a = null;
}
}
if (empty($resRefs[$h])) {
$resRefs[$h] = $stub;
} else {
$stub = $resRefs[$h];
++$stub->refCount;
$a = null;
}
break;
}
case 'resource':
case 'unknown type':
case 'resource (closed)':
if (empty($resRefs[$h = (int) $v])) {
$stub = new Stub();
$stub->type = Stub::TYPE_RESOURCE;
if ('Unknown' === $stub->class = $zval['resource_type'] ?: @get_resource_type($v)) {
$stub->class = 'Closed';
}
$stub->value = $v;
$stub->handle = $h;
$a = $this->castResource($stub, 0 < $i);
$stub->value = null;
if (0 <= $maxItems && $maxItems <= $pos) {
$stub->cut = count($a);
$a = null;
}
}
if (empty($resRefs[$h])) {
$resRefs[$h] = $stub;
} else {
$stub = $resRefs[$h];
++$stub->refCount;
$a = null;
}
break;
}
if (isset($stub)) {
if ($zval['zval_isref']) {
if ($useExt) {
$queue[$i][$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub();
$v->value = $stub;
} else {
$step[$k] = new Stub();
$step[$k]->value = $stub;
$h = spl_object_hash($step[$k]);
$queue[$i][$k] = $hardRefs[$h] = &$step[$k];
$values[$h] = $v;
}
$queue[$i][$k]->handle = ++$refs;
} else {
$queue[$i][$k] = $stub;
}
if (isset($stub)) {
if ($zval['zval_isref']) {
if ($useExt) {
$vals[$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub();
$v->value = $stub;
} else {
$refs[$k] = new Stub();
$refs[$k]->value = $stub;
$h = spl_object_hash($refs[$k]);
$vals[$k] = $hardRefs[$h] = &$refs[$k];
$values[$h] = $v;
}
$vals[$k]->handle = ++$refsCounter;
} else {
$vals[$k] = $stub;
}
if ($a) {
if ($i && 0 <= $maxItems) {
$k = count($a);
if ($pos < $maxItems) {
if ($maxItems < $pos += $k) {
$a = array_slice($a, 0, $maxItems - $pos);
if ($stub->cut >= 0) {
$stub->cut += $pos - $maxItems;
}
}
} else {
if ($stub->cut >= 0) {
$stub->cut += $k;
}
$stub = $a = null;
unset($arrayRefs[$len]);
continue;
}
}
$queue[$len] = $a;
$stub->position = $len++;
}
$stub = $a = null;
} elseif ($zval['zval_isref']) {
if ($useExt) {
$queue[$i][$k] = $hardRefs[$zval['zval_hash']] = new Stub();
$queue[$i][$k]->value = $v;
} else {
$step[$k] = $queue[$i][$k] = new Stub();
$step[$k]->value = $v;
$h = spl_object_hash($step[$k]);
$hardRefs[$h] = &$step[$k];
$values[$h] = $v;
}
$queue[$i][$k]->handle = ++$refs;
}
}
if ($a) {
if ($i && 0 <= $maxItems) {
$k = count($a);
if ($pos < $maxItems) {
if ($maxItems < $pos += $k) {
$a = array_slice($a, 0, $maxItems - $pos);
if ($stub->cut >= 0) {
$stub->cut += $pos - $maxItems;
}
}
} else {
if ($stub->cut >= 0) {
$stub->cut += $k;
}
$stub = $a = null;
unset($arrayRefs[$len]);
continue;
}
}
$queue[$len] = $a;
$stub->position = $len++;
}
$stub = $a = null;
} elseif ($zval['zval_isref']) {
if ($useExt) {
$vals[$k] = $hardRefs[$zval['zval_hash']] = new Stub();
$vals[$k]->value = $v;
} else {
$refs[$k] = $vals[$k] = new Stub();
$refs[$k]->value = $v;
$h = spl_object_hash($refs[$k]);
$hardRefs[$h] = &$refs[$k];
$values[$h] = $v;
}
$vals[$k]->handle = ++$refsCounter;
}
}
if (isset($arrayRefs[$i])) {
if ($indexed) {
$arrayRefs[$i]->class = Stub::ARRAY_INDEXED;
}
unset($arrayRefs[$i]);
}
}
if ($fromObjCast) {
$refs = $vals;
$vals = array();
$j = -1;
foreach ($queue[$i] as $k => $v) {
foreach (array($k => $v) as $a => $v) {
}
if ($a !== $k) {
$vals = (object) $vals;
$vals->{$k} = $refs[++$j];
$vals = (array) $vals;
} else {
$vals[$k] = $refs[++$j];
}
}
}
foreach ($values as $h => $v) {
$hardRefs[$h] = $v;
}
$queue[$i] = $vals;
return $queue;
}
if (isset($arrayRefs[$i])) {
if ($indexed) {
$arrayRefs[$i]->class = Stub::ARRAY_INDEXED;
}
unset($arrayRefs[$i]);
}
}
private static function initHashMask()
{
$obj = (object) array();
self::$hashOffset = 16 - PHP_INT_SIZE;
self::$hashMask = -1;
foreach ($values as $h => $v) {
$hardRefs[$h] = $v;
}
if (defined('HHVM_VERSION')) {
self::$hashOffset += 16;
} else {
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
$obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush');
foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && in_array($frame['function'], $obFuncs)) {
$frame['line'] = 0;
break;
}
}
if (!empty($frame['line'])) {
ob_start();
debug_zval_dump($obj);
self::$hashMask = substr(ob_get_clean(), 17);
}
}
return $queue;
}
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), self::$hashOffset, PHP_INT_SIZE));
}
private static function initHashMask()
{
$obj = (object) array();
self::$hashOffset = 16 - PHP_INT_SIZE;
self::$hashMask = -1;
if (defined('HHVM_VERSION')) {
self::$hashOffset += 16;
} else {
// check if we are nested in an output buffering handler to prevent a fatal error with ob_start() below
$obFuncs = array('ob_clean', 'ob_end_clean', 'ob_flush', 'ob_end_flush', 'ob_get_contents', 'ob_get_flush');
foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
if (isset($frame['function'][0]) && !isset($frame['class']) && 'o' === $frame['function'][0] && in_array($frame['function'], $obFuncs)) {
$frame['line'] = 0;
break;
}
}
if (!empty($frame['line'])) {
ob_start();
debug_zval_dump($obj);
self::$hashMask = (int) substr(ob_get_clean(), 17);
}
}
self::$hashMask ^= hexdec(substr(spl_object_hash($obj), self::$hashOffset, PHP_INT_SIZE));
}
}

View File

@ -21,156 +21,181 @@ use Symfony\Component\VarDumper\Cloner\DumperInterface;
*/
abstract class AbstractDumper implements DataDumperInterface, DumperInterface
{
public static $defaultOutput = 'php://output';
const DUMP_LIGHT_ARRAY = 1;
const DUMP_STRING_LENGTH = 2;
protected $line = '';
protected $lineDumper;
protected $outputStream;
protected $decimalPoint; // This is locale dependent
protected $indentPad = ' ';
public static $defaultOutput = 'php://output';
private $charset;
protected $line = '';
protected $lineDumper;
protected $outputStream;
protected $decimalPoint; // This is locale dependent
protected $indentPad = ' ';
protected $flags;
/**
* @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.
*/
public function __construct($output = null, $charset = null)
{
$this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8');
$this->decimalPoint = (string) 0.5;
$this->decimalPoint = $this->decimalPoint[1];
$this->setOutput($output ?: static::$defaultOutput);
if (!$output && is_string(static::$defaultOutput)) {
static::$defaultOutput = $this->outputStream;
}
}
private $charset;
/**
* Sets the output destination of the dumps.
*
* @param callable|resource|string $output A line dumper callable, an opened stream or an output path.
*
* @return callable|resource|string The previous output destination.
*/
public function setOutput($output)
{
$prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
/**
* @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 int $flags A bit field of static::DUMP_* constants to fine tune dumps representation
*/
public function __construct($output = null, $charset = null, $flags = 0)
{
$this->flags = (int) $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->setOutput($output ?: static::$defaultOutput);
if (!$output && is_string(static::$defaultOutput)) {
static::$defaultOutput = $this->outputStream;
}
}
if (is_callable($output)) {
$this->outputStream = null;
$this->lineDumper = $output;
} else {
if (is_string($output)) {
$output = fopen($output, 'wb');
}
$this->outputStream = $output;
$this->lineDumper = array($this, 'echoLine');
}
/**
* Sets the output destination of the dumps.
*
* @param callable|resource|string $output A line dumper callable, an opened stream or an output path
*
* @return callable|resource|string The previous output destination
*/
public function setOutput($output)
{
$prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
return $prev;
}
if (is_callable($output)) {
$this->outputStream = null;
$this->lineDumper = $output;
} else {
if (is_string($output)) {
$output = fopen($output, 'wb');
}
$this->outputStream = $output;
$this->lineDumper = array($this, 'echoLine');
}
/**
* Sets the default character encoding to use for non-UTF8 strings.
*
* @param string $charset The default character encoding to use for non-UTF8 strings.
*
* @return string The previous charset.
*/
public function setCharset($charset)
{
$prev = $this->charset;
return $prev;
}
$charset = strtoupper($charset);
$charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset;
/**
* Sets the default character encoding to use for non-UTF8 strings.
*
* @param string $charset The default character encoding to use for non-UTF8 strings
*
* @return string The previous charset
*/
public function setCharset($charset)
{
$prev = $this->charset;
$this->charset = $charset;
$charset = strtoupper($charset);
$charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset;
return $prev;
}
$this->charset = $charset;
/**
* Sets the indentation pad string.
*
* @param string $pad A string the will be prepended to dumped lines, repeated by nesting level.
*
* @return string The indent pad.
*/
public function setIndentPad($pad)
{
$prev = $this->indentPad;
$this->indentPad = $pad;
return $prev;
}
return $prev;
}
/**
* Sets the indentation pad string.
*
* @param string $pad A string the will be prepended to dumped lines, repeated by nesting level
*
* @return string The indent pad
*/
public function setIndentPad($pad)
{
$prev = $this->indentPad;
$this->indentPad = $pad;
/**
* Dumps a Data object.
*
* @param Data $data A Data object.
* @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path.
*/
public function dump(Data $data, $output = null)
{
$exception = null;
if ($output) {
$prevOutput = $this->setOutput($output);
}
try {
$data->dump($this);
$this->dumpLine(-1);
} catch (\Exception $exception) {
// Re-thrown below
}
if ($output) {
$this->setOutput($prevOutput);
}
if (null !== $exception) {
throw $exception;
}
}
return $prev;
}
/**
* Dumps the current line.
*
* @param int $depth The recursive depth in the dumped structure for the line being dumped.
*/
protected function dumpLine($depth)
{
call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
$this->line = '';
}
/**
* 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'];
/**
* Generic line dumper callback.
*
* @param string $line The line to write.
* @param int $depth The recursive depth in the dumped structure.
*/
protected function echoLine($line, $depth, $indentPad)
{
if (-1 !== $depth) {
fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n");
}
}
if ($returnDump = true === $output) {
$output = fopen('php://memory', 'r+b');
}
if ($output) {
$prevOutput = $this->setOutput($output);
}
try {
$data->dump($this);
$this->dumpLine(-1);
/**
* Converts a non-UTF-8 string to UTF-8.
*
* @param string $s The non-UTF-8 string to convert.
*
* @return string The string converted to UTF-8.
*/
protected function utf8Encode($s)
{
if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) {
return $c;
}
if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) {
return $c;
}
if ($returnDump) {
$result = stream_get_contents($output, -1, 0);
fclose($output);
return iconv('CP850', 'UTF-8', $s);
}
return $result;
}
} finally {
if ($output) {
$this->setOutput($prevOutput);
}
}
}
/**
* Dumps the current line.
*
* @param int $depth The recursive depth in the dumped structure for the line being dumped
*/
protected function dumpLine($depth)
{
call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
$this->line = '';
}
/**
* Generic line dumper callback.
*
* @param string $line The line to write
* @param int $depth The recursive depth in the dumped structure
* @param string $indentPad The line indent pad
*/
protected function echoLine($line, $depth, $indentPad)
{
if (-1 !== $depth) {
fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n");
}
}
/**
* Converts a non-UTF-8 string to UTF-8.
*
* @param string $s The non-UTF-8 string to convert
*
* @return string The string converted to UTF-8
*/
protected function utf8Encode($s)
{
if (preg_match('//u', $s)) {
return $s;
}
if (!function_exists('iconv')) {
throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.');
}
if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) {
return $c;
}
if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) {
return $c;
}
return iconv('CP850', 'UTF-8', $s);
}
}

View File

@ -20,452 +20,470 @@ use Symfony\Component\VarDumper\Cloner\Cursor;
*/
class CliDumper extends AbstractDumper
{
public static $defaultColors;
public static $defaultOutput = 'php://stdout';
public static $defaultColors;
public static $defaultOutput = 'php://stdout';
protected $colors;
protected $maxStringWidth = 0;
protected $styles = array(
// See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
'default' => '38;5;208',
'num' => '1;38;5;38',
'const' => '1;38;5;208',
'str' => '1;38;5;113',
'note' => '38;5;38',
'ref' => '38;5;247',
'public' => '',
'protected' => '',
'private' => '',
'meta' => '38;5;170',
'key' => '38;5;113',
'index' => '38;5;38',
);
protected $colors;
protected $maxStringWidth = 0;
protected $styles = array(
// See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
'default' => '38;5;208',
'num' => '1;38;5;38',
'const' => '1;38;5;208',
'str' => '1;38;5;113',
'note' => '38;5;38',
'ref' => '38;5;247',
'public' => '',
'protected' => '',
'private' => '',
'meta' => '38;5;170',
'key' => '38;5;113',
'index' => '38;5;38',
);
protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/';
protected static $controlCharsMap = array(
"\t" => '\t',
"\n" => '\n',
"\v" => '\v',
"\f" => '\f',
"\r" => '\r',
"\033" => '\e',
);
protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/';
protected static $controlCharsMap = array(
"\t" => '\t',
"\n" => '\n',
"\v" => '\v',
"\f" => '\f',
"\r" => '\r',
"\033" => '\e',
);
/**
* {@inheritdoc}
*/
public function __construct($output = null, $charset = null)
{
parent::__construct($output, $charset);
/**
* {@inheritdoc}
*/
public function __construct($output = null, $charset = null, $flags = 0)
{
parent::__construct($output, $charset, $flags);
if ('\\' === DIRECTORY_SEPARATOR && false !== @getenv('ANSICON')) {
// Use only the base 16 xterm colors when using ANSICON
$this->setStyles(array(
'default' => '31',
'num' => '1;34',
'const' => '1;31',
'str' => '1;32',
'note' => '34',
'ref' => '1;30',
'meta' => '35',
'key' => '32',
'index' => '34',
));
}
}
if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) {
// Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI
$this->setStyles(array(
'default' => '31',
'num' => '1;34',
'const' => '1;31',
'str' => '1;32',
'note' => '34',
'ref' => '1;30',
'meta' => '35',
'key' => '32',
'index' => '34',
));
}
}
/**
* Enables/disables colored output.
*
* @param bool $colors
*/
public function setColors($colors)
{
$this->colors = (bool) $colors;
}
/**
* Enables/disables colored output.
*
* @param bool $colors
*/
public function setColors($colors)
{
$this->colors = (bool) $colors;
}
/**
* Sets the maximum number of characters per line for dumped strings.
*
* @param int $maxStringWidth
*/
public function setMaxStringWidth($maxStringWidth)
{
$this->maxStringWidth = (int) $maxStringWidth;
}
/**
* Sets the maximum number of characters per line for dumped strings.
*
* @param int $maxStringWidth
*/
public function setMaxStringWidth($maxStringWidth)
{
$this->maxStringWidth = (int) $maxStringWidth;
}
/**
* Configures styles.
*
* @param array $styles A map of style names to style definitions.
*/
public function setStyles(array $styles)
{
$this->styles = $styles + $this->styles;
}
/**
* Configures styles.
*
* @param array $styles A map of style names to style definitions
*/
public function setStyles(array $styles)
{
$this->styles = $styles + $this->styles;
}
/**
* {@inheritdoc}
*/
public function dumpScalar(Cursor $cursor, $type, $value)
{
$this->dumpKey($cursor);
/**
* {@inheritdoc}
*/
public function dumpScalar(Cursor $cursor, $type, $value)
{
$this->dumpKey($cursor);
$style = 'const';
$attr = array();
$style = 'const';
$attr = $cursor->attr;
switch ($type) {
case 'integer':
$style = 'num';
break;
switch ($type) {
case 'default':
$style = 'default';
break;
case 'double':
$style = 'num';
case 'integer':
$style = 'num';
break;
switch (true) {
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)) {
$value .= $this->decimalPoint.'0';
}
break;
}
break;
case 'double':
$style = 'num';
case 'NULL':
$value = 'null';
break;
switch (true) {
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)) {
$value .= $this->decimalPoint.'0';
}
break;
}
break;
case 'boolean':
$value = $value ? 'true' : 'false';
break;
case 'NULL':
$value = 'null';
break;
default:
$attr['value'] = isset($value[0]) && !preg_match('//u', $value) ? $this->utf8Encode($value) : $value;
$value = isset($type[0]) && !preg_match('//u', $type) ? $this->utf8Encode($type) : $type;
break;
}
case 'boolean':
$value = $value ? 'true' : 'false';
break;
$this->line .= $this->style($style, $value, $attr);
default:
$attr += array('value' => $this->utf8Encode($value));
$value = $this->utf8Encode($type);
break;
}
$this->dumpLine($cursor->depth, true);
}
$this->line .= $this->style($style, $value, $attr);
/**
* {@inheritdoc}
*/
public function dumpString(Cursor $cursor, $str, $bin, $cut)
{
$this->dumpKey($cursor);
$this->dumpLine($cursor->depth, true);
}
if ($bin) {
$str = $this->utf8Encode($str);
}
if ('' === $str) {
$this->line .= '""';
$this->dumpLine($cursor->depth, true);
} else {
$attr = array(
'length' => 0 <= $cut ? iconv_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]);
$str[0] .= "\n";
}
$m = count($str) - 1;
$i = $lineCut = 0;
/**
* {@inheritdoc}
*/
public function dumpString(Cursor $cursor, $str, $bin, $cut)
{
$this->dumpKey($cursor);
$attr = $cursor->attr;
if ($bin) {
$this->line .= 'b';
}
if ($bin) {
$str = $this->utf8Encode($str);
}
if ('' === $str) {
$this->line .= '""';
$this->dumpLine($cursor->depth, true);
} else {
$attr += array(
'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]);
$str[0] .= "\n";
}
$m = count($str) - 1;
$i = $lineCut = 0;
if ($m) {
$this->line .= '"""';
$this->dumpLine($cursor->depth);
} else {
$this->line .= '"';
}
if (self::DUMP_STRING_LENGTH & $this->flags) {
$this->line .= '('.$attr['length'].') ';
}
if ($bin) {
$this->line .= 'b';
}
foreach ($str as $str) {
if ($i < $m) {
$str .= "\n";
}
if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = iconv_strlen($str, 'UTF-8')) {
$str = iconv_substr($str, 0, $this->maxStringWidth, 'UTF-8');
$lineCut = $len - $this->maxStringWidth;
}
if ($m && 0 < $cursor->depth) {
$this->line .= $this->indentPad;
}
if ('' !== $str) {
$this->line .= $this->style('str', $str, $attr);
}
if ($i++ == $m) {
if ($m) {
if ('' !== $str) {
$this->dumpLine($cursor->depth);
if (0 < $cursor->depth) {
$this->line .= $this->indentPad;
}
}
$this->line .= '"""';
} else {
$this->line .= '"';
}
if ($cut < 0) {
$this->line .= '…';
$lineCut = 0;
} elseif ($cut) {
$lineCut += $cut;
}
}
if ($lineCut) {
$this->line .= '…'.$lineCut;
$lineCut = 0;
}
if ($m) {
$this->line .= '"""';
$this->dumpLine($cursor->depth);
} else {
$this->line .= '"';
}
$this->dumpLine($cursor->depth, $i > $m);
}
}
}
foreach ($str as $str) {
if ($i < $m) {
$str .= "\n";
}
if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = mb_strlen($str, 'UTF-8')) {
$str = mb_substr($str, 0, $this->maxStringWidth, 'UTF-8');
$lineCut = $len - $this->maxStringWidth;
}
if ($m && 0 < $cursor->depth) {
$this->line .= $this->indentPad;
}
if ('' !== $str) {
$this->line .= $this->style('str', $str, $attr);
}
if ($i++ == $m) {
if ($m) {
if ('' !== $str) {
$this->dumpLine($cursor->depth);
if (0 < $cursor->depth) {
$this->line .= $this->indentPad;
}
}
$this->line .= '"""';
} else {
$this->line .= '"';
}
if ($cut < 0) {
$this->line .= '…';
$lineCut = 0;
} elseif ($cut) {
$lineCut += $cut;
}
}
if ($lineCut) {
$this->line .= '…'.$lineCut;
$lineCut = 0;
}
/**
* {@inheritdoc}
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
$this->dumpKey($cursor);
$this->dumpLine($cursor->depth, $i > $m);
}
}
}
if (!preg_match('//u', $class)) {
$class = $this->utf8Encode($class);
}
if (Cursor::HASH_OBJECT === $type) {
$prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{';
} elseif (Cursor::HASH_RESOURCE === $type) {
$prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' ');
} else {
$prefix = $class ? $this->style('note', 'array:'.$class).' [' : '[';
}
/**
* {@inheritdoc}
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
$this->dumpKey($cursor);
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));
} elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) {
$prefix .= $this->style('ref', '&'.$cursor->hardRefTo, array('count' => $cursor->hardRefCount));
} elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) {
$prefix = substr($prefix, 0, -1);
}
$class = $this->utf8Encode($class);
if (Cursor::HASH_OBJECT === $type) {
$prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{';
} elseif (Cursor::HASH_RESOURCE === $type) {
$prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' ');
} else {
$prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '[';
}
$this->line .= $prefix;
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));
} elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) {
$prefix .= $this->style('ref', '&'.$cursor->hardRefTo, array('count' => $cursor->hardRefCount));
} elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) {
$prefix = substr($prefix, 0, -1);
}
if ($hasChild) {
$this->dumpLine($cursor->depth);
}
}
$this->line .= $prefix;
/**
* {@inheritdoc}
*/
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 ? '}' : ''));
$this->dumpLine($cursor->depth, true);
}
if ($hasChild) {
$this->dumpLine($cursor->depth);
}
}
/**
* 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.
*/
protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut)
{
if ($cut) {
$this->line .= ' …';
if (0 < $cut) {
$this->line .= $cut;
}
if ($hasChild) {
$this->dumpLine($cursor->depth + 1);
}
}
}
/**
* {@inheritdoc}
*/
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 ? '}' : ''));
$this->dumpLine($cursor->depth, true);
}
/**
* Dumps a key in a hash structure.
*
* @param Cursor $cursor The Cursor position in the dump.
*/
protected function dumpKey(Cursor $cursor)
{
if (null !== $key = $cursor->hashKey) {
if ($cursor->hashKeyIsBinary) {
$key = $this->utf8Encode($key);
}
$attr = array('binary' => $cursor->hashKeyIsBinary);
$bin = $cursor->hashKeyIsBinary ? 'b' : '';
$style = 'key';
switch ($cursor->hashType) {
default:
case Cursor::HASH_INDEXED:
$style = 'index';
case Cursor::HASH_ASSOC:
if (is_int($key)) {
$this->line .= $this->style($style, $key).' => ';
} else {
$this->line .= $bin.'"'.$this->style($style, $key).'" => ';
}
break;
/**
* 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
*/
protected function dumpEllipsis(Cursor $cursor, $hasChild, $cut)
{
if ($cut) {
$this->line .= ' …';
if (0 < $cut) {
$this->line .= $cut;
}
if ($hasChild) {
$this->dumpLine($cursor->depth + 1);
}
}
}
case Cursor::HASH_RESOURCE:
$key = "\0~\0".$key;
// No break;
case Cursor::HASH_OBJECT:
if (!isset($key[0]) || "\0" !== $key[0]) {
$this->line .= '+'.$bin.$this->style('public', $key).': ';
} elseif (0 < strpos($key, "\0", 1)) {
$key = explode("\0", substr($key, 1), 2);
/**
* Dumps a key in a hash structure.
*
* @param Cursor $cursor The Cursor position in the dump
*/
protected function dumpKey(Cursor $cursor)
{
if (null !== $key = $cursor->hashKey) {
if ($cursor->hashKeyIsBinary) {
$key = $this->utf8Encode($key);
}
$attr = array('binary' => $cursor->hashKeyIsBinary);
$bin = $cursor->hashKeyIsBinary ? 'b' : '';
$style = 'key';
switch ($cursor->hashType) {
default:
case Cursor::HASH_INDEXED:
if (self::DUMP_LIGHT_ARRAY & $this->flags) {
break;
}
$style = 'index';
case Cursor::HASH_ASSOC:
if (is_int($key)) {
$this->line .= $this->style($style, $key).' => ';
} else {
$this->line .= $bin.'"'.$this->style($style, $key).'" => ';
}
break;
switch ($key[0]) {
case '+': // User inserted keys
$attr['dynamic'] = true;
$this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": ';
break 2;
case '~':
$style = 'meta';
break;
case '*':
$style = 'protected';
$bin = '#'.$bin;
break;
default:
$attr['class'] = $key[0];
$style = 'private';
$bin = '-'.$bin;
break;
}
case Cursor::HASH_RESOURCE:
$key = "\0~\0".$key;
// No break;
case Cursor::HASH_OBJECT:
if (!isset($key[0]) || "\0" !== $key[0]) {
$this->line .= '+'.$bin.$this->style('public', $key).': ';
} elseif (0 < strpos($key, "\0", 1)) {
$key = explode("\0", substr($key, 1), 2);
$this->line .= $bin.$this->style($style, $key[1], $attr).': ';
} else {
// This case should not happen
$this->line .= '-'.$bin.'"'.$this->style('private', $key, array('class' => '')).'": ';
}
break;
}
switch ($key[0][0]) {
case '+': // User inserted keys
$attr['dynamic'] = true;
$this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": ';
break 2;
case '~':
$style = 'meta';
if (isset($key[0][1])) {
parse_str(substr($key[0], 1), $attr);
$attr += array('binary' => $cursor->hashKeyIsBinary);
}
break;
case '*':
$style = 'protected';
$bin = '#'.$bin;
break;
default:
$attr['class'] = $key[0];
$style = 'private';
$bin = '-'.$bin;
break;
}
if ($cursor->hardRefTo) {
$this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), array('count' => $cursor->hardRefCount)).' ';
}
}
}
$this->line .= $bin.$this->style($style, $key[1], $attr).': ';
} else {
// This case should not happen
$this->line .= '-'.$bin.'"'.$this->style('private', $key, array('class' => '')).'": ';
}
break;
}
/**
* Decorates a value with some style.
*
* @param string $style The type of style being applied.
* @param string $value The value being styled.
* @param array $attr Optional context information.
*
* @return string The value with style decoration.
*/
protected function style($style, $value, $attr = array())
{
if (null === $this->colors) {
$this->colors = $this->supportsColors();
}
if ($cursor->hardRefTo) {
$this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), array('count' => $cursor->hardRefCount)).' ';
}
}
}
$style = $this->styles[$style];
/**
* Decorates a value with some style.
*
* @param string $style The type of style being applied
* @param string $value The value being styled
* @param array $attr Optional context information
*
* @return string The value with style decoration
*/
protected function style($style, $value, $attr = array())
{
if (null === $this->colors) {
$this->colors = $this->supportsColors();
}
$map = static::$controlCharsMap;
$startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : '';
$endCchr = $this->colors ? "\033[m\033[{$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]));
} while (isset($c[++$i]));
$style = $this->styles[$style];
return $s.$endCchr;
}, $value, -1, $cchrCount);
$map = static::$controlCharsMap;
$startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : '';
$endCchr = $this->colors ? "\033[m\033[{$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]));
} while (isset($c[++$i]));
if ($this->colors) {
if ($cchrCount && "\033" === $value[0]) {
$value = substr($value, strlen($startCchr));
} else {
$value = "\033[{$style}m".$value;
}
if ($cchrCount && $endCchr === substr($value, -strlen($endCchr))) {
$value = substr($value, 0, -strlen($endCchr));
} else {
$value .= "\033[{$this->styles['default']}m";
}
}
return $s.$endCchr;
}, $value, -1, $cchrCount);
return $value;
}
if ($this->colors) {
if ($cchrCount && "\033" === $value[0]) {
$value = substr($value, strlen($startCchr));
} else {
$value = "\033[{$style}m".$value;
}
if ($cchrCount && $endCchr === substr($value, -strlen($endCchr))) {
$value = substr($value, 0, -strlen($endCchr));
} else {
$value .= "\033[{$this->styles['default']}m";
}
}
/**
* @return bool Tells if the current output stream supports ANSI colors or not.
*/
protected function supportsColors()
{
if ($this->outputStream !== static::$defaultOutput) {
return @(is_resource($this->outputStream) && function_exists('posix_isatty') && posix_isatty($this->outputStream));
}
if (null !== static::$defaultColors) {
return static::$defaultColors;
}
if (isset($_SERVER['argv'][1])) {
$colors = $_SERVER['argv'];
$i = count($colors);
while (--$i > 0) {
if (isset($colors[$i][5])) {
switch ($colors[$i]) {
case '--ansi':
case '--color':
case '--color=yes':
case '--color=force':
case '--color=always':
return static::$defaultColors = true;
return $value;
}
case '--no-ansi':
case '--color=no':
case '--color=none':
case '--color=never':
return static::$defaultColors = false;
}
}
}
}
/**
* @return bool Tells if the current output stream supports ANSI colors or not
*/
protected function supportsColors()
{
if ($this->outputStream !== static::$defaultOutput) {
return @(is_resource($this->outputStream) && function_exists('posix_isatty') && posix_isatty($this->outputStream));
}
if (null !== static::$defaultColors) {
return static::$defaultColors;
}
if (isset($_SERVER['argv'][1])) {
$colors = $_SERVER['argv'];
$i = count($colors);
while (--$i > 0) {
if (isset($colors[$i][5])) {
switch ($colors[$i]) {
case '--ansi':
case '--color':
case '--color=yes':
case '--color=force':
case '--color=always':
return static::$defaultColors = true;
if ('\\' === DIRECTORY_SEPARATOR) {
static::$defaultColors = @(false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI') || 'xterm' === getenv('TERM'));
} elseif (function_exists('posix_isatty')) {
$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;
static::$defaultColors = @posix_isatty($h);
} else {
static::$defaultColors = false;
}
case '--no-ansi':
case '--color=no':
case '--color=none':
case '--color=never':
return static::$defaultColors = false;
}
}
}
}
return static::$defaultColors;
}
if ('\\' === DIRECTORY_SEPARATOR) {
static::$defaultColors = @(
'10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM')
);
} elseif (function_exists('posix_isatty')) {
$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;
static::$defaultColors = @posix_isatty($h);
} else {
static::$defaultColors = false;
}
/**
* {@inheritdoc}
*/
protected function dumpLine($depth, $endOfValue = false)
{
if ($this->colors) {
$this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line);
}
parent::dumpLine($depth);
}
return static::$defaultColors;
}
/**
* {@inheritdoc}
*/
protected function dumpLine($depth, $endOfValue = false)
{
if ($this->colors) {
$this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line);
}
parent::dumpLine($depth);
}
}

View File

@ -20,10 +20,10 @@ use Symfony\Component\VarDumper\Cloner\Data;
*/
interface DataDumperInterface
{
/**
* Dumps a Data object.
*
* @param Data $data A Data object.
*/
public function dump(Data $data);
/**
* Dumps a Data object.
*
* @param Data $data A Data object
*/
public function dump(Data $data);
}

View File

@ -21,103 +21,114 @@ use Symfony\Component\VarDumper\Cloner\Data;
*/
class HtmlDumper extends CliDumper
{
public static $defaultOutput = 'php://output';
public static $defaultOutput = 'php://output';
protected $dumpHeader;
protected $dumpPrefix = '<pre class=sf-dump id=%s data-indent-pad="%s">';
protected $dumpSuffix = '</pre><script>Sfdump("%s")</script>';
protected $dumpId = 'sf-dump';
protected $colors = true;
protected $headerIsDumped = false;
protected $lastDepth = -1;
protected $styles = array(
'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:100000; word-break: normal',
'num' => 'font-weight:bold; color:#1299DA',
'const' => 'font-weight:bold',
'str' => 'font-weight:bold; color:#56DB3A',
'note' => 'color:#1299DA',
'ref' => 'color:#A0A0A0',
'public' => 'color:#FFFFFF',
'protected' => 'color:#FFFFFF',
'private' => 'color:#FFFFFF',
'meta' => 'color:#B729D9',
'key' => 'color:#56DB3A',
'index' => 'color:#1299DA',
);
protected $dumpHeader;
protected $dumpPrefix = '<pre class=sf-dump id=%s data-indent-pad="%s">';
protected $dumpSuffix = '</pre><script>Sfdump(%s)</script>';
protected $dumpId = 'sf-dump';
protected $colors = true;
protected $headerIsDumped = false;
protected $lastDepth = -1;
protected $styles = array(
'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: normal',
'num' => 'font-weight:bold; color:#1299DA',
'const' => 'font-weight:bold',
'str' => 'font-weight:bold; color:#56DB3A',
'note' => 'color:#1299DA',
'ref' => 'color:#A0A0A0',
'public' => 'color:#FFFFFF',
'protected' => 'color:#FFFFFF',
'private' => 'color:#FFFFFF',
'meta' => 'color:#B729D9',
'key' => 'color:#56DB3A',
'index' => 'color:#1299DA',
'ellipsis' => 'color:#FF8400',
);
/**
* {@inheritdoc}
*/
public function __construct($output = null, $charset = null)
{
AbstractDumper::__construct($output, $charset);
$this->dumpId = 'sf-dump-'.mt_rand();
}
private $displayOptions = array(
'maxDepth' => 1,
'maxStringLength' => 160,
'fileLinkFormat' => null,
);
private $extraDisplayOptions = array();
/**
* {@inheritdoc}
*/
public function setOutput($output)
{
if ($output !== $prev = parent::setOutput($output)) {
$this->headerIsDumped = false;
}
/**
* {@inheritdoc}
*/
public function __construct($output = null, $charset = null, $flags = 0)
{
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');
}
return $prev;
}
/**
* {@inheritdoc}
*/
public function setStyles(array $styles)
{
$this->headerIsDumped = false;
$this->styles = $styles + $this->styles;
}
/**
* {@inheritdoc}
*/
public function setStyles(array $styles)
{
$this->headerIsDumped = false;
$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->headerIsDumped = false;
$this->displayOptions = $displayOptions + $this->displayOptions;
}
/**
* Sets an HTML header that will be dumped once in the output stream.
*
* @param string $header An HTML string.
*/
public function setDumpHeader($header)
{
$this->dumpHeader = $header;
}
/**
* Sets an HTML header that will be dumped once in the output stream.
*
* @param string $header An HTML string
*/
public function setDumpHeader($header)
{
$this->dumpHeader = $header;
}
/**
* Sets an HTML prefix and suffix that will encapse every single dump.
*
* @param string $prefix The prepended HTML string.
* @param string $suffix The appended HTML string.
*/
public function setDumpBoundaries($prefix, $suffix)
{
$this->dumpPrefix = $prefix;
$this->dumpSuffix = $suffix;
}
/**
* Sets an HTML prefix and suffix that will encapse every single dump.
*
* @param string $prefix The prepended HTML string
* @param string $suffix The appended HTML string
*/
public function setDumpBoundaries($prefix, $suffix)
{
$this->dumpPrefix = $prefix;
$this->dumpSuffix = $suffix;
}
/**
* {@inheritdoc}
*/
public function dump(Data $data, $output = null)
{
parent::dump($data, $output);
$this->dumpId = 'sf-dump-'.mt_rand();
}
/**
* {@inheritdoc}
*/
public function dump(Data $data, $output = null, array $extraDisplayOptions = array())
{
$this->extraDisplayOptions = $extraDisplayOptions;
$result = parent::dump($data, $output);
$this->dumpId = 'sf-dump-'.mt_rand();
/**
* Dumps the HTML header.
*/
protected function getDumpHeader()
{
$this->headerIsDumped = true;
return $result;
}
if (null !== $this->dumpHeader) {
return $this->dumpHeader;
}
/**
* Dumps the HTML header.
*/
protected function getDumpHeader()
{
$this->headerIsDumped = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
$line = <<<'EOHTML'
if (null !== $this->dumpHeader) {
return $this->dumpHeader;
}
$line = str_replace('{$options}', json_encode($this->displayOptions, JSON_FORCE_OBJECT), <<<'EOHTML'
<script>
Sfdump = window.Sfdump || (function (doc) {
@ -173,15 +184,30 @@ function toggle(a, recursive) {
return true;
};
return function (root) {
return function (root, x) {
root = doc.getElementById(root);
var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || ' ').replace(rxEsc, '\\$1')+')+', 'm'),
options = {$options},
elt = root.getElementsByTagName('A'),
len = elt.length,
i = 0, s, h,
t = [];
while (i < len) t.push(elt[i++]);
for (i in x) {
options[i] = x[i];
}
function a(e, f) {
addEventListener(root, e, function (e) {
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);
}
});
};
@ -193,15 +219,17 @@ return function (root) {
refStyle.innerHTML = '';
}
});
a('mouseover', function (a) {
if (a = idRx.exec(a.className)) {
a('mouseover', function (a, e, c) {
if (c) {
e.target.style.cursor = "pointer";
} else if (a = idRx.exec(a.className)) {
try {
refStyle.innerHTML = 'pre.sf-dump .'+a[0]+'{background-color: #B729D9; color: #FFF !important; border-radius: 2px}';
} catch (e) {
}
}
});
a('click', function (a, e) {
a('click', function (a, e, c) {
if (/\bsf-dump-toggle\b/.test(a.className)) {
e.preventDefault();
if (!toggle(a, isCtrlKey(e))) {
@ -222,7 +250,8 @@ return function (root) {
}
}
if (doc.getSelection) {
if (c) {
} else if (doc.getSelection) {
try {
doc.getSelection().removeAllRanges();
} catch (e) {
@ -231,31 +260,24 @@ return function (root) {
} else {
doc.selection.empty();
}
} else if (/\bsf-dump-str-toggle\b/.test(a.className)) {
e.preventDefault();
e = a.parentNode.parentNode;
e.className = e.className.replace(/sf-dump-str-(expand|collapse)/, a.parentNode.className);
}
});
var indentRx = new RegExp('^('+(root.getAttribute('data-indent-pad') || ' ').replace(rxEsc, '\\$1')+')+', 'm'),
elt = root.getElementsByTagName('A'),
len = elt.length,
i = 0,
t = [];
while (i < len) t.push(elt[i++]);
elt = root.getElementsByTagName('SAMP');
len = elt.length;
i = 0;
while (i < len) t.push(elt[i++]);
root = t;
len = t.length;
i = t = 0;
while (i < len) {
elt = root[i];
if ("SAMP" == elt.tagName) {
elt.className = "sf-dump-expanded";
for (i = 0; i < len; ++i) {
elt = t[i];
if ('SAMP' == elt.tagName) {
elt.className = 'sf-dump-expanded';
a = elt.previousSibling || {};
if ('A' != a.tagName) {
a = doc.createElement('A');
@ -267,19 +289,24 @@ return function (root) {
a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children';
a.innerHTML += '<span>▼</span>';
a.className += ' sf-dump-toggle';
x = 1;
if ('sf-dump' != elt.parentNode.className) {
x += elt.parentNode.getAttribute('data-depth')/1;
}
elt.setAttribute('data-depth', x);
if (x > options.maxDepth) {
toggle(a);
}
} else if ("sf-dump-ref" == elt.className && (a = elt.getAttribute('href'))) {
} else if ('sf-dump-ref' == elt.className && (a = elt.getAttribute('href'))) {
a = a.substr(1);
elt.className += ' '+a;
if (/[\[{]$/.test(elt.previousSibling.nodeValue)) {
a = a != elt.nextSibling.id && doc.getElementById(a);
try {
t = a.nextSibling;
s = a.nextSibling;
elt.appendChild(a);
t.parentNode.insertBefore(a, t);
s.parentNode.insertBefore(a, s);
if (/^[@#]/.test(elt.innerHTML)) {
elt.innerHTML += ' <span>▶</span>';
} else {
@ -295,13 +322,38 @@ return function (root) {
}
}
}
++i;
}
if (0 >= options.maxStringLength) {
return;
}
try {
elt = root.querySelectorAll('.sf-dump-str');
len = elt.length;
i = 0;
t = [];
while (i < len) t.push(elt[i++]);
len = t.length;
for (i = 0; i < len; ++i) {
elt = t[i];
s = elt.innerText || elt.textContent;
x = s.length - options.maxStringLength;
if (0 < x) {
h = elt.innerHTML;
elt[elt.innerText ? 'innerText' : 'textContent'] = s.substring(0, options.maxStringLength);
elt.className += ' sf-dump-str-collapse';
elt.innerHTML = '<span class=sf-dump-str-collapse>'+h+'<a class="sf-dump-ref sf-dump-str-toggle" title="Collapse"> ◀</a></span>'+
'<span class=sf-dump-str-expand>'+elt.innerHTML+'<a class="sf-dump-ref sf-dump-str-toggle" title="'+x+' remaining characters"> ▶</a></span>';
}
}
} catch (e) {
}
};
})(document);
</script>
<style>
</script><style>
pre.sf-dump {
display: block;
white-space: pre;
@ -323,130 +375,179 @@ pre.sf-dump a {
cursor: pointer;
border: 0;
outline: none;
color: inherit;
}
EOHTML;
foreach ($this->styles as $class => $style) {
$line .= 'pre.sf-dump'.('default' !== $class ? ' .sf-dump-'.$class : '').'{'.$style.'}';
}
return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader;
}
/**
* {@inheritdoc}
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
parent::enterHash($cursor, $type, $class, false);
if ($hasChild) {
if ($cursor->refIndex) {
$r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2;
$r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex;
$this->line .= sprintf('<samp id=%s-ref%s>', $this->dumpId, $r);
} else {
$this->line .= '<samp>';
}
$this->dumpLine($cursor->depth);
}
}
/**
* {@inheritdoc}
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut)
{
$this->dumpEllipsis($cursor, $hasChild, $cut);
if ($hasChild) {
$this->line .= '</samp>';
}
parent::leaveHash($cursor, $type, $class, $hasChild, 0);
}
/**
* {@inheritdoc}
*/
protected function style($style, $value, $attr = array())
{
if ('' === $value) {
return '';
}
$v = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
if ('ref' === $style) {
if (empty($attr['count'])) {
return sprintf('<a class=sf-dump-ref>%s</a>', $v);
}
$r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1);
return sprintf('<a class=sf-dump-ref href=#%s-ref%s title="%d occurrences">%s</a>', $this->dumpId, $r, 1 + $attr['count'], $v);
}
if ('const' === $style && array_key_exists('value', $attr)) {
$style .= sprintf(' title="%s"', htmlspecialchars(json_encode($attr['value']), ENT_QUOTES, 'UTF-8'));
} 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="%s%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 ('protected' === $style) {
$style .= ' title="Protected property"';
} elseif ('private' === $style) {
$style .= sprintf(' title="Private property defined in class:&#10;`%s`"', $attr['class']);
}
$map = static::$controlCharsMap;
$style = "<span class=sf-dump-{$style}>";
$v = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $style) {
$s = '</span>';
$c = $c[$i = 0];
do {
$s .= isset($map[$c[$i]]) ? $map[$c[$i]] : sprintf('\x%02X', ord($c[$i]));
} while (isset($c[++$i]));
return $s.$style;
}, $v, -1, $cchrCount);
if ($cchrCount && '<' === $v[0]) {
$v = substr($v, 7);
} else {
$v = $style.$v;
}
if ($cchrCount && '>' === substr($v, -1)) {
$v = substr($v, 0, -strlen($style));
} else {
$v .= '</span>';
}
return $v;
}
/**
* {@inheritdoc}
*/
protected function dumpLine($depth, $endOfValue = false)
{
if (-1 === $this->lastDepth) {
$this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line;
}
if (!$this->headerIsDumped) {
$this->line = $this->getDumpHeader().$this->line;
}
if (-1 === $depth) {
$this->line .= sprintf($this->dumpSuffix, $this->dumpId);
}
$this->lastDepth = $depth;
$this->line = mb_convert_encoding($this->line, 'HTML-ENTITIES', 'UTF-8');
if (-1 === $depth) {
AbstractDumper::dumpLine(0);
}
AbstractDumper::dumpLine($depth);
}
pre.sf-dump .sf-dump-ellipsis {
display: inline-block;
overflow: visible;
text-overflow: ellipsis;
max-width: 5em;
white-space: nowrap;
overflow: hidden;
vertical-align: top;
}
pre.sf-dump code {
display:inline;
padding:0;
background:none;
}
.sf-dump-str-collapse .sf-dump-str-collapse {
display: none;
}
.sf-dump-str-expand .sf-dump-str-expand {
display: none;
}
EOHTML
);
foreach ($this->styles as $class => $style) {
$line .= 'pre.sf-dump'.('default' === $class ? ', pre.sf-dump' : '').' .sf-dump-'.$class.'{'.$style.'}';
}
return $this->dumpHeader = preg_replace('/\s+/', ' ', $line).'</style>'.$this->dumpHeader;
}
/**
* {@inheritdoc}
*/
public function enterHash(Cursor $cursor, $type, $class, $hasChild)
{
parent::enterHash($cursor, $type, $class, false);
if ($hasChild) {
if ($cursor->refIndex) {
$r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2;
$r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex;
$this->line .= sprintf('<samp id=%s-ref%s>', $this->dumpId, $r);
} else {
$this->line .= '<samp>';
}
$this->dumpLine($cursor->depth);
}
}
/**
* {@inheritdoc}
*/
public function leaveHash(Cursor $cursor, $type, $class, $hasChild, $cut)
{
$this->dumpEllipsis($cursor, $hasChild, $cut);
if ($hasChild) {
$this->line .= '</samp>';
}
parent::leaveHash($cursor, $type, $class, $hasChild, 0);
}
/**
* {@inheritdoc}
*/
protected function style($style, $value, $attr = array())
{
if ('' === $value) {
return '';
}
$v = esc($value);
if ('ref' === $style) {
if (empty($attr['count'])) {
return sprintf('<a class=sf-dump-ref>%s</a>', $v);
}
$r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1);
return sprintf('<a class=sf-dump-ref href=#%s-ref%s title="%d occurrences">%s</a>', $this->dumpId, $r, 1 + $attr['count'], $v);
}
if ('const' === $style && isset($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 ('protected' === $style) {
$style .= ' title="Protected property"';
} elseif ('meta' === $style && isset($attr['title'])) {
$style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title'])));
} elseif ('private' === $style) {
$style .= sprintf(' title="Private property defined in class:&#10;`%s`"', esc($this->utf8Encode($attr['class'])));
}
$map = static::$controlCharsMap;
if (isset($attr['ellipsis'])) {
$label = esc(substr($value, -$attr['ellipsis']));
$style = str_replace(' title="', " title=\"$v\n", $style);
$v = sprintf('<span class=sf-dump-ellipsis>%s</span>%s', substr($v, 0, -strlen($label)), $label);
}
$v = "<span class=sf-dump-{$style}>".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) {
$s = '<span class=sf-dump-default>';
$c = $c[$i = 0];
do {
$s .= isset($map[$c[$i]]) ? $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)) {
$attr['href'] = $href;
}
if (isset($attr['href'])) {
$v = sprintf('<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', esc($this->utf8Encode($attr['href'])), $v);
}
if (isset($attr['lang'])) {
$v = sprintf('<code class="%s">%s</code>', esc($attr['lang']), $v);
}
return $v;
}
/**
* {@inheritdoc}
*/
protected function dumpLine($depth, $endOfValue = false)
{
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)) {
$this->line = $this->getDumpHeader().$this->line;
}
if (-1 === $depth) {
$args = array('"'.$this->dumpId.'"');
if ($this->extraDisplayOptions) {
$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');
if (-1 === $depth) {
AbstractDumper::dumpLine(0);
}
AbstractDumper::dumpLine($depth);
}
private function getSourceLink($file, $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 false;
}
}
function esc($str)
{
return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

View File

@ -1,4 +1,4 @@
Copyright (c) 2014-2015 Fabien Potencier
Copyright (c) 2014-2017 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

@ -1,14 +1,15 @@
Symfony mechanism for exploring and dumping PHP variables
=========================================================
VarDumper Component
===================
This component provides a mechanism that allows exploring then dumping
any PHP variable.
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`.
It handles scalars, objects and resources properly, taking hard and soft
references into account. More than being immune to infinite recursion
problems, it allows dumping where references link to each other.
It explores recursive structures using a breadth-first algorithm.
Resources
---------
The component exposes all the parts involved in the different steps of
cloning then dumping a PHP variable, while applying size limits and having
specialized output formats and methods.
* [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

@ -19,27 +19,30 @@ use Symfony\Component\VarDumper\Dumper\CliDumper;
*/
trait VarDumperTestTrait
{
public function assertDumpEquals($dump, $data, $message = '')
{
$this->assertSame(rtrim($dump), $this->getDump($data), $message);
}
public function assertDumpEquals($dump, $data, $message = '')
{
$this->assertSame(rtrim($dump), $this->getDump($data), $message);
}
public function assertDumpMatchesFormat($dump, $data, $message = '')
{
$this->assertStringMatchesFormat(rtrim($dump), $this->getDump($data), $message);
}
public function assertDumpMatchesFormat($dump, $data, $message = '')
{
$this->assertStringMatchesFormat(rtrim($dump), $this->getDump($data), $message);
}
protected function getDump($data)
{
$h = fopen('php://memory', 'r+b');
$cloner = new VarCloner();
$cloner->setMaxItems(-1);
$dumper = new CliDumper($h);
$dumper->setColors(false);
$dumper->dump($cloner->cloneVar($data)->withRefHandles(false));
$data = stream_get_contents($h, -1, 0);
fclose($h);
protected function getDump($data, $key = null)
{
$flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0;
$flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0;
return rtrim($data);
}
$cloner = new VarCloner();
$cloner->setMaxItems(-1);
$dumper = new CliDumper(null, null, $flags);
$dumper->setColors(false);
$data = $cloner->cloneVar($data)->withRefHandles(false);
if (null !== $key && null === $data = $data->seek($key)) {
return;
}
return rtrim($dumper->dump($data, true));
}
}

View File

@ -11,170 +11,171 @@
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 \PHPUnit_Framework_TestCase
class CasterTest extends TestCase
{
use VarDumperTestTrait;
use VarDumperTestTrait;
private $referenceArray = array(
'null' => null,
'empty' => false,
'public' => 'pub',
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0*\0protected" => 'prot',
"\0Foo\0private" => 'priv',
);
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);
}
/**
* @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));
}
$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 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'),
),
);
}
/**
* @requires PHP 7.0
*/
public function testAnonymousClass()
{
$c = eval('return new class extends stdClass { private $foo = "foo"; };');
/**
* @requires PHP 7.0
*/
public function testAnonymousClass()
{
$c = eval('return new class extends stdClass { private $foo = "foo"; };');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
$this->assertDumpMatchesFormat(
<<<'EOTXT'
stdClass@anonymous {
-foo: "foo"
}
EOTXT
, $c
);
, $c
);
$c = eval('return new class { private $foo = "foo"; };');
$c = eval('return new class { private $foo = "foo"; };');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
$this->assertDumpMatchesFormat(
<<<'EOTXT'
@anonymous {
-foo: "foo"
}
EOTXT
, $c
);
}
, $c
);
}
}

View File

@ -0,0 +1,225 @@
<?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\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: 27
-trace: {
%sExceptionCasterTest.php:27: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: $ref = array('foo');
: $e = $this->getTestException('foo', $ref);
:
arguments: {
$msg: "foo"
&$ref: array:1 [ …1]
}
}
%A
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
$this->assertSame(array('foo'), $ref);
}
public function testSeek()
{
$e = $this->getTestException(2);
$expectedDump = <<<'EODUMP'
{
%sExceptionCasterTest.php:27: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: {
: $e = $this->getTestException(2);
:
arguments: {
$msg: 2
}
}
%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: 27
-trace: {
%sExceptionCasterTest.php:27: {
: {
: return new \Exception(''.$msg);
: }
}
%sExceptionCasterTest.php:%d: {
: {
: $e = $this->getTestException(1);
: ExceptionCaster::$traceArgs = false;
}
%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: 27
-trace: {
%sExceptionCasterTest.php: 27
%sExceptionCasterTest.php: %d
%A
EODUMP;
$this->assertDumpMatchesFormat($expectedDump, $e);
}
public function testHtmlDump()
{
$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>%sTests</span>%eCaster%eExceptionCasterTest.php</span>"
#<span class=sf-dump-protected title="Protected property">line</span>: <span class=sf-dump-num>27</span>
-<span class=sf-dump-private title="Private property defined in class:&#10;`Exception`">trace</span>: {<samp>
<span class=sf-dump-meta title="%sExceptionCasterTest.php
Stack level %d."><span class=sf-dump-ellipsis>%sVarDumper%eTests</span>%eCaster%eExceptionCasterTest.php</span>: <span class=sf-dump-num>27</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);
}
}

View File

@ -11,47 +11,54 @@
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 \PHPUnit_Framework_TestCase
class PdoCasterTest extends TestCase
{
/**
* @requires extension pdo_sqlite
*/
public function testCastPdo()
{
$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array($pdo)));
use VarDumperTestTrait;
$cast = PdoCaster::castPdo($pdo, array(), new Stub(), false);
/**
* @requires extension pdo_sqlite
*/
public function testCastPdo()
{
$pdo = new \PDO('sqlite::memory:');
$pdo->setAttribute(\PDO::ATTR_STATEMENT_CLASS, array('PDOStatement', array($pdo)));
$this->assertInstanceOf('Symfony\Component\VarDumper\Caster\EnumStub', $cast["\0~\0attributes"]);
$cast = PdoCaster::castPdo($pdo, array(), new Stub(), false);
$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);
$this->assertInstanceOf('Symfony\Component\VarDumper\Caster\EnumStub', $cast["\0~\0attributes"]);
$xCast = array(
"\0~\0inTransaction" => $pdo->inTransaction(),
"\0~\0attributes" => array(
'CASE' => $attr['CASE'],
'ERRMODE' => $attr['ERRMODE'],
'PERSISTENT' => false,
'DRIVER_NAME' => 'sqlite',
'ORACLE_NULLS' => $attr['ORACLE_NULLS'],
'CLIENT_VERSION' => $pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION),
'SERVER_VERSION' => $pdo->getAttribute(\PDO::ATTR_SERVER_VERSION),
'STATEMENT_CLASS' => array('PDOStatement'),
'DEFAULT_FETCH_MODE' => $attr['DEFAULT_FETCH_MODE'],
),
);
unset($cast["\0~\0attributes"]['STATEMENT_CLASS'][1]);
$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);
$this->assertSame($xCast, $cast);
}
$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

@ -0,0 +1,85 @@
<?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();
if (defined('HHVM_VERSION_ID')) {
$xCast = <<<'EODUMP'
Redis {
#host: ""
%A
}
EODUMP;
} else {
$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']);
}
if (defined('HHVM_VERSION_ID')) {
$xCast = <<<'EODUMP'
Redis {
#host: "127.0.0.1"
%A
}
EODUMP;
} else {
$xCast = <<<'EODUMP'
Redis {
+"socket": Redis Socket Buffer resource
isConnected: true
host: "127.0.0.1"
port: 6379
auth: null
dbNum: 0
timeout: 0.0
persistentId: null
options: {
READ_TIMEOUT: 0.0
SERIALIZER: NONE
PREFIX: null
SCAN: NORETRY
}
}
EODUMP;
}
$this->assertDumpMatchesFormat($xCast, $redis);
}
}

View File

@ -11,22 +11,24 @@
namespace Symfony\Component\VarDumper\Tests\Caster;
use PHPUnit\Framework\TestCase;
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 \PHPUnit_Framework_TestCase
class ReflectionCasterTest extends TestCase
{
use VarDumperTestTrait;
use VarDumperTestTrait;
public function testReflectionCaster()
{
$var = new \ReflectionClass('ReflectionClass');
public function testReflectionCaster()
{
$var = new \ReflectionClass('ReflectionClass');
$this->assertDumpMatchesFormat(
<<<'EOTXT'
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionClass {
+name: "ReflectionClass"
%Aimplements: array:%d [
@ -49,23 +51,23 @@ ReflectionClass {
"export" => ReflectionMethod {
+name: "export"
+class: "ReflectionClass"
parameters: {
%A parameters: {
$%s: ReflectionParameter {
%A position: 0
%A
}
EOTXT
, $var
);
}
, $var
);
}
public function testClosureCaster()
{
$a = $b = 123;
$var = function ($x) use ($a, &$b) {};
public function testClosureCaster()
{
$a = $b = 123;
$var = function ($x) use ($a, &$b) {};
$this->assertDumpMatchesFormat(
<<<EOTXT
$this->assertDumpMatchesFormat(
<<<EOTXT
Closure {
%Aparameters: {
\$x: {}
@ -75,60 +77,60 @@ Closure {
\$b: & 123
}
file: "%sReflectionCasterTest.php"
line: "65 to 65"
line: "67 to 67"
}
EOTXT
, $var
);
}
, $var
);
}
public function testReflectionParameter()
{
$var = new \ReflectionParameter(__NAMESPACE__.'\reflectionParameterFixture', 0);
public function testReflectionParameter()
{
$var = new \ReflectionParameter(__NAMESPACE__.'\reflectionParameterFixture', 0);
$this->assertDumpMatchesFormat(
<<<'EOTXT'
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionParameter {
+name: "arg1"
position: 0
typeHint: "Symfony\Component\VarDumper\Tests\Caster\NotExistingClass"
typeHint: "Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass"
default: null
}
EOTXT
, $var
);
}
, $var
);
}
/**
* @requires PHP 7.0
*/
public function testReflectionParameterScalar()
{
$f = eval('return function (int $a) {};');
$var = new \ReflectionParameter($f, 0);
/**
* @requires PHP 7.0
*/
public function testReflectionParameterScalar()
{
$f = eval('return function (int $a) {};');
$var = new \ReflectionParameter($f, 0);
$this->assertDumpMatchesFormat(
<<<'EOTXT'
$this->assertDumpMatchesFormat(
<<<'EOTXT'
ReflectionParameter {
+name: "a"
position: 0
typeHint: "int"
}
EOTXT
, $var
);
}
, $var
);
}
/**
* @requires PHP 7.0
*/
public function testReturnType()
{
$f = eval('return function ():int {};');
$line = __LINE__ - 1;
/**
* @requires PHP 7.0
*/
public function testReturnType()
{
$f = eval('return function ():int {};');
$line = __LINE__ - 1;
$this->assertDumpMatchesFormat(
<<<EOTXT
$this->assertDumpMatchesFormat(
<<<EOTXT
Closure {
returnType: "int"
class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest"
@ -137,92 +139,97 @@ Closure {
line: "1 to 1"
}
EOTXT
, $f
);
}
, $f
);
}
/**
* @requires PHP 7.0
*/
public function testGenerator()
{
$g = new GeneratorDemo();
$g = $g->baz();
$r = new \ReflectionGenerator($g);
/**
* @requires PHP 7.0
*/
public function testGenerator()
{
if (extension_loaded('xdebug')) {
$this->markTestSkipped('xdebug is active');
}
$xDump = <<<'EODUMP'
$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: """
{\n
yield from bar();\n
}\n
"""
%sGeneratorDemo.php:14: {
: {
: yield from bar();
: }
}
}
}
closed: false
}
EODUMP;
$this->assertDumpMatchesFormat($xDump, $g);
$this->assertDumpMatchesFormat($expectedDump, $generator);
foreach ($g as $v) {
break;
}
foreach ($generator as $v) {
break;
}
$xDump = <<<'EODUMP'
$expectedDump = <<<'EODUMP'
array:2 [
0 => ReflectionGenerator {
this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { }
trace: {
3. Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() ==> yield(): {
src: {
%sGeneratorDemo.php:9: """
{\n
yield 1;\n
}\n
"""
}
%sGeneratorDemo.php:9: {
: {
: yield 1;
: }
}
2. Symfony\Component\VarDumper\Tests\Fixtures\bar() ==> Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): {
src: {
%sGeneratorDemo.php:20: """
{\n
yield from GeneratorDemo::foo();\n
}\n
"""
}
%sGeneratorDemo.php:20: {
: {
: yield from GeneratorDemo::foo();
: }
}
1. Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() ==> Symfony\Component\VarDumper\Tests\Fixtures\bar(): {
src: {
%sGeneratorDemo.php:14: """
{\n
yield from bar();\n
}\n
"""
}
%sGeneratorDemo.php:14: {
: {
: yield from bar();
: }
}
}
closed: false
}
1 => Generator {
executing: {
Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): {
%sGeneratorDemo.php:10: """
yield 1;\n
}\n
\n
"""
%sGeneratorDemo.php:10: {
: yield 1;
: }
:
}
}
}
closed: false
}
]
EODUMP;
$this->assertDumpMatchesFormat($xDump, array($r, $r->getExecutingGenerator()));
}
$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(NotExistingClass $arg1 = null, $arg2)
function reflectionParameterFixture(NotLoadableClass $arg1 = null, $arg2)
{
}

View File

@ -11,19 +11,20 @@
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 \PHPUnit_Framework_TestCase
class SplCasterTest extends TestCase
{
use VarDumperTestTrait;
use VarDumperTestTrait;
public function getCastFileInfoTests()
{
return array(
array(__FILE__, <<<'EOTXT'
public function getCastFileInfoTests()
{
return array(
array(__FILE__, <<<'EOTXT'
SplFileInfo {
%Apath: "%sCaster"
filename: "SplCasterTest.php"
@ -48,8 +49,8 @@ SplFileInfo {
link: false
%A}
EOTXT
),
array('https://google.com/about', <<<'EOTXT'
),
array('https://google.com/about', <<<'EOTXT'
SplFileInfo {
%Apath: "https://google.com"
filename: "about"
@ -57,29 +58,23 @@ SplFileInfo {
pathname: "https://google.com/about"
extension: ""
realPath: false
writable: false
readable: false
executable: false
file: false
dir: false
link: false
%A}
EOTXT
),
);
}
),
);
}
/** @dataProvider getCastFileInfoTests */
public function testCastFileInfo($file, $dump)
{
$this->assertDumpMatchesFormat($dump, new \SplFileInfo($file));
}
/** @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'
public function testCastFileObject()
{
$var = new \SplFileObject(__FILE__);
$var->setFlags(\SplFileObject::DROP_NEW_LINE | \SplFileObject::SKIP_EMPTY);
$dump = <<<'EOTXT'
SplFileObject {
%Apath: "%sCaster"
filename: "SplCasterTest.php"
@ -102,10 +97,10 @@ SplFileObject {
file: true
dir: false
link: false
%AcsvControl: array:2 [
%AcsvControl: array:%d [
0 => ","
1 => """
]
%A]
flags: DROP_NEW_LINE|SKIP_EMPTY
maxLineLen: 0
fstat: array:26 [
@ -121,6 +116,32 @@ SplFileObject {
key: 0
}
EOTXT;
$this->assertDumpMatchesFormat($dump, $var);
}
$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'),
);
}
}

View File

@ -0,0 +1,171 @@
<?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" target="_blank" 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 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" target="_blank" rel="noopener noreferrer"><span class=sf-dump-str title="5 characters">hello</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>Symfony\Component\VarDumper\Tests\Caster</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" target="_blank" rel="noopener noreferrer"><span class=sf-dump-str title="5 characters">hello</span></a>"
</samp>]
</bar>
EODUMP;
$this->assertStringMatchesFormat($expectedDump, $dump);
}
}

View File

@ -0,0 +1,248 @@
<?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

@ -11,43 +11,46 @@
namespace Symfony\Component\VarDumper\Tests;
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 \PHPUnit_Framework_TestCase
class CliDumperTest extends TestCase
{
use VarDumperTestTrait;
use VarDumperTestTrait;
public function testGet()
{
require __DIR__.'/Fixtures/dumb-var.php';
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']);
$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);
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'];
ob_start();
$dumper->dump($data);
$out = ob_get_clean();
$out = preg_replace('/[ \t]+$/m', '', $out);
$intMax = PHP_INT_MAX;
$res = (int) $var['res'];
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
array:24 [
"number" => 1
0 => &1 null
@ -62,15 +65,12 @@ array:24 [
7 => b"é\\x00"
"[]" => []
"res" => stream resource {@{$res}
wrapper_type: "plainfile"
%A wrapper_type: "plainfile"
stream_type: "STDIO"
mode: "r"
unread_bytes: 0
seekable: true
timed_out: false
blocked: true
eof: false
options: []
%A options: []
}
"obj" => Symfony\Component\VarDumper\Tests\Fixture\DumbFoo {#%d
+foo: "foo"
@ -105,20 +105,20 @@ array:24 [
]
EOTXT
,
$out
);
}
,
$out
);
}
/**
* @requires extension xml
*/
public function testXmlResource()
{
$var = xml_parser_create();
/**
* @requires extension xml
*/
public function testXmlResource()
{
$var = xml_parser_create();
$this->assertDumpMatchesFormat(
<<<EOTXT
$this->assertDumpMatchesFormat(
<<<'EOTXT'
xml resource {
current_byte_index: %i
current_column_number: %i
@ -126,199 +126,257 @@ xml resource {
error_code: XML_ERROR_NONE
}
EOTXT
,
$var
);
}
,
$var
);
}
public function testClosedResource()
{
if (defined('HHVM_VERSION') && HHVM_VERSION_ID < 30600) {
$this->markTestSkipped();
}
public function testJsonCast()
{
$var = (array) json_decode('{"0":{},"1":null}');
foreach ($var as &$v) {
}
$var[] = &$v;
$var[''] = 2;
$var = fopen(__FILE__, 'r');
fclose($var);
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
);
}
}
$dumper = new CliDumper('php://output');
$dumper->setColors(false);
$cloner = new VarCloner();
$data = $cloner->cloneVar($var);
public function testObjectCast()
{
$var = (object) array(1 => 1);
$var->{1} = 2;
ob_start();
$dumper->dump($data);
$out = ob_get_clean();
$res = (int) $var;
if (\PHP_VERSION_ID >= 70200) {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
{
+"1": 2
}
EOTXT
,
$var
);
} else {
$this->assertDumpMatchesFormat(
<<<'EOTXT'
{
+1: 1
+"1": 2
}
EOTXT
,
$var
);
}
}
$this->assertStringMatchesFormat(
<<<EOTXT
Unknown resource @{$res}
public function testClosedResource()
{
if (defined('HHVM_VERSION') && HHVM_VERSION_ID < 30600) {
$this->markTestSkipped();
}
$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
);
}
,
$out
);
}
public function testThrowingCaster()
{
$out = fopen('php://memory', 'r+b');
public function testFlags()
{
putenv('DUMP_LIGHT_ARRAY=1');
putenv('DUMP_STRING_LENGTH=1');
require_once __DIR__.'/Fixtures/Twig.php';
$twig = new \__TwigTemplate_VarDumperFixture_u75a09(new \Twig_Environment(new \Twig_Loader_Filesystem()));
$var = array(
range(1, 3),
array('foo', 2 => 'bar'),
);
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$cloner->addCasters(array(
':stream' => function ($res, $a) {
unset($a['wrapper_data']);
$this->assertDumpEquals(
<<<EOTXT
[
[
1
2
3
]
[
0 => (3) "foo"
2 => (3) "bar"
]
]
EOTXT
,
$var
);
return $a;
},
));
$cloner->addCasters(array(
':stream' => eval('return function () use ($twig) {
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_Runtime $e) {
} catch (\Twig\Error\RuntimeError $e) {
throw $e->getPrevious();
}
};'),
));
$line = __LINE__ - 2;
$ref = (int) $out;
));
$ref = (int) $out;
$data = $cloner->cloneVar($out);
$dumper->dump($data, $out);
rewind($out);
$out = stream_get_contents($out);
$data = $cloner->cloneVar($out);
$dumper->dump($data, $out);
$out = stream_get_contents($out, -1, 0);
if (method_exists($twig, 'getSource')) {
$twig = <<<EOTXT
foo.twig:2: """
foo bar\\n
twig source\\n
\\n
"""
EOTXT;
} else {
$twig = '';
}
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
stream resource {@{$ref}
wrapper_type: "PHP"
: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
#message: "Unexpected Exception thrown from a caster: Foobar"
-trace: {
%sTwig.php:2: {
: foo bar
: twig source
:
}
%sTemplate.php:%d: {
: try {
: \$this->doDisplay(\$context, \$blocks);
: } catch (Twig%sError \$e) {
}
%sTemplate.php:%d: {
: {
: \$this->displayWithErrorHandling(\$this->env->mergeGlobals(\$context), array_merge(\$this->blocks, \$blocks));
: }
}
%sTemplate.php:%d: {
: try {
: \$this->display(\$context);
: } catch (%s \$e) {
}
%sCliDumperTest.php:%d: {
%A
}
}
}
%Awrapper_type: "PHP"
stream_type: "MEMORY"
mode: "%s+b"
unread_bytes: 0
seekable: true
uri: "php://memory"
timed_out: false
blocked: true
eof: false
options: []
: Symfony\Component\VarDumper\Exception\ThrowingCasterException {{$r}
#message: "Unexpected Exception thrown from a caster: Foobar"
-trace: {
%d. __TwigTemplate_VarDumperFixture_u75a09->doDisplay() ==> new Exception(): {
src: {
%sTwig.php:19: """
// line 2\\n
throw new \Exception('Foobar');\\n
}\\n
"""
{$twig} }
}
%d. Twig_Template->displayWithErrorHandling() ==> __TwigTemplate_VarDumperFixture_u75a09->doDisplay(): {
src: {
%sTemplate.php:%d: """
try {\\n
\$this->doDisplay(\$context, \$blocks);\\n
} catch (Twig_Error \$e) {\\n
"""
}
}
%d. Twig_Template->display() ==> Twig_Template->displayWithErrorHandling(): {
src: {
%sTemplate.php:%d: """
{\\n
\$this->displayWithErrorHandling(\$this->env->mergeGlobals(\$context), array_merge(\$this->blocks, \$blocks));\\n
}\\n
"""
}
}
%d. Twig_Template->render() ==> Twig_Template->display(): {
src: {
%sTemplate.php:%d: """
try {\\n
\$this->display(\$context);\\n
} catch (Exception \$e) {\\n
"""
}
}
%d. %slosure%s() ==> Twig_Template->render(): {
src: {
%sCliDumperTest.php:{$line}: """
}\\n
};'),\\n
));\\n
"""
}
}
}
}
%Aoptions: []
}
EOTXT
,
$out
);
}
,
$out
);
}
public function testRefsInProperties()
{
$var = (object) array('foo' => 'foo');
$var->bar = &$var->foo;
public function testRefsInProperties()
{
$var = (object) array('foo' => 'foo');
$var->bar = &$var->foo;
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$out = fopen('php://memory', 'r+b');
$data = $cloner->cloneVar($var);
$dumper->dump($data, $out);
rewind($out);
$out = stream_get_contents($out);
$data = $cloner->cloneVar($var);
$out = $dumper->dump($data, true);
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
$r = defined('HHVM_VERSION') ? '' : '#%d';
$this->assertStringMatchesFormat(
<<<EOTXT
{{$r}
+"foo": &1 "foo"
+"bar": &1 "foo"
}
EOTXT
,
$out
);
}
,
$out
);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
* @requires PHP 5.6
*/
public function testSpecialVars56()
{
$var = $this->getSpecialVars();
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
* @requires PHP 5.6
*/
public function testSpecialVars56()
{
$var = $this->getSpecialVars();
$this->assertDumpEquals(
<<<EOTXT
$this->assertDumpEquals(
<<<'EOTXT'
array:3 [
0 => array:1 [
0 => &1 array:1 [
@ -333,38 +391,38 @@ array:3 [
2 => &2 array:1 [&2]
]
EOTXT
,
$var
);
}
,
$var
);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testGlobalsNoExt()
{
$var = $this->getSpecialVars();
unset($var[0]);
$out = '';
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testGlobalsNoExt()
{
$var = $this->getSpecialVars();
unset($var[0]);
$out = '';
$dumper = new CliDumper(function ($line, $depth) use (&$out) {
if ($depth >= 0) {
$out .= str_repeat(' ', $depth).$line."\n";
}
});
$dumper->setColors(false);
$cloner = new VarCloner();
$dumper = new CliDumper(function ($line, $depth) use (&$out) {
if ($depth >= 0) {
$out .= str_repeat(' ', $depth).$line."\n";
}
});
$dumper->setColors(false);
$cloner = new VarCloner();
$refl = new \ReflectionProperty($cloner, 'useExt');
$refl->setAccessible(true);
$refl->setValue($cloner, false);
$refl = new \ReflectionProperty($cloner, 'useExt');
$refl->setAccessible(true);
$refl->setValue($cloner, false);
$data = $cloner->cloneVar($var);
$dumper->dump($data);
$data = $cloner->cloneVar($var);
$dumper->dump($data);
$this->assertSame(
<<<EOTXT
$this->assertSame(
<<<'EOTXT'
array:2 [
1 => array:1 [
"GLOBALS" => &1 array:1 [
@ -375,38 +433,38 @@ array:2 [
]
EOTXT
,
$out
);
}
,
$out
);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testBuggyRefs()
{
if (PHP_VERSION_ID >= 50600) {
$this->markTestSkipped('PHP 5.6 fixed refs counting');
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testBuggyRefs()
{
if (\PHP_VERSION_ID >= 50600) {
$this->markTestSkipped('PHP 5.6 fixed refs counting');
}
$var = $this->getSpecialVars();
$var = $var[0];
$var = $this->getSpecialVars();
$var = $var[0];
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$dumper = new CliDumper();
$dumper->setColors(false);
$cloner = new VarCloner();
$data = $cloner->cloneVar($var)->withMaxDepth(3);
$out = '';
$dumper->dump($data, function ($line, $depth) use (&$out) {
if ($depth >= 0) {
$out .= str_repeat(' ', $depth).$line."\n";
}
});
$data = $cloner->cloneVar($var)->withMaxDepth(3);
$out = '';
$dumper->dump($data, function ($line, $depth) use (&$out) {
if ($depth >= 0) {
$out .= str_repeat(' ', $depth).$line."\n";
}
});
$this->assertSame(
<<<EOTXT
$this->assertSame(
<<<'EOTXT'
array:1 [
0 => array:1 [
0 => array:1 [
@ -416,26 +474,41 @@ array:1 [
]
EOTXT
,
$out
);
}
,
$out
);
}
private function getSpecialVars()
{
foreach (array_keys($GLOBALS) as $var) {
if ('GLOBALS' !== $var) {
unset($GLOBALS[$var]);
}
}
public function testIncompleteClass()
{
$unserializeCallbackHandler = ini_set('unserialize_callback_func', null);
$var = unserialize('O:8:"Foo\Buzz":0:{}');
ini_set('unserialize_callback_func', $unserializeCallbackHandler);
$var = function &() {
$var = array();
$var[] = &$var;
$this->assertDumpMatchesFormat(
<<<EOTXT
__PHP_Incomplete_Class(Foo\Buzz) {}
EOTXT
,
$var
);
}
return $var;
};
private function getSpecialVars()
{
foreach (array_keys($GLOBALS) as $var) {
if ('GLOBALS' !== $var) {
unset($GLOBALS[$var]);
}
}
return array($var(), $GLOBALS, &$GLOBALS);
}
$var = function &() {
$var = array();
$var[] = &$var;
return $var;
};
return array($var(), $GLOBALS, &$GLOBALS);
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,10 @@
<?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

@ -11,44 +11,45 @@
namespace Symfony\Component\VarDumper\Tests;
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 \PHPUnit_Framework_TestCase
class HtmlDumperTest extends TestCase
{
public function testGet()
{
require __DIR__.'/Fixtures/dumb-var.php';
public function testGet()
{
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']);
$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);
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'];
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'];
$r = defined('HHVM_VERSION') ? '' : '<a class=sf-dump-ref>#%d</a>';
$this->assertStringMatchesFormat(
<<<EOTXT
$r = defined('HHVM_VERSION') ? '' : '<a class=sf-dump-ref>#%d</a>';
$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>
@ -59,26 +60,24 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase
<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>\\n"
<span class=sf-dump-key>7</span> => b"<span class=sf-dump-str title="2 binary or non-UTF-8 characters">&%s;</span>\\x00"
"<span class=sf-dump-key>str</span>" => "<span class=sf-dump-str title="5 characters">d&%s;j&%s;<span class=sf-dump-default>\\n</span></span>"
<span class=sf-dump-key>7</span> => b"<span class=sf-dump-str title="2 binary or non-UTF-8 characters">&%s;<span class=sf-dump-default>\\x00</span></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>
<span class=sf-dump-meta>wrapper_type</span>: "<span class=sf-dump-str title="9 characters">plainfile</span>"
%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>
<span class=sf-dump-meta>timed_out</span>: <span class=sf-dump-const>false</span>
<span class=sf-dump-meta>blocked</span>: <span class=sf-dump-const>true</span>
<span class=sf-dump-meta>eof</span>: <span class=sf-dump-const>false</span>
<span class=sf-dump-meta>options</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</span> {{$r}<samp>
<span class=sf-dump-meta>class</span>: "<span class=sf-dump-str title="48 characters">Symfony\Component\VarDumper\Tests\HtmlDumperTest</span>"
<span class=sf-dump-meta>class</span>: "<span class=sf-dump-str title="Symfony\Component\VarDumper\Tests\HtmlDumperTest
48 characters"><span class=sf-dump-ellipsis>Symfony\Component\VarDumper\Tests</span>\HtmlDumperTest</span>"
<span class=sf-dump-meta>this</span>: <abbr title="Symfony\Component\VarDumper\Tests\HtmlDumperTest" class=sf-dump-note>HtmlDumperTest</abbr> {{$r} &%s;}
<span class=sf-dump-meta>parameters</span>: {<samp>
<span class=sf-dump-meta>\$a</span>: {}
@ -87,7 +86,8 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase
<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="%d characters">{$var['file']}</span>"
<span class=sf-dump-meta>file</span>: "<span class=sf-dump-str title="{$var['file']}
%d characters"><span class=sf-dump-ellipsis>%sTests</span>%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>
@ -107,36 +107,57 @@ class HtmlDumperTest extends \PHPUnit_Framework_TestCase
</bar>
EOTXT
,
,
$out
);
}
$out
);
}
public function testCharset()
{
$var = mb_convert_encoding('Словарь', 'CP1251', 'UTF-8');
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();
$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);
$data = $cloner->cloneVar($var);
$out = fopen('php://memory', 'r+b');
$dumper->dump($data, $out);
rewind($out);
$out = stream_get_contents($out);
$this->assertStringMatchesFormat(
<<<EOTXT
$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
);
}
$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

@ -11,20 +11,21 @@
namespace Symfony\Component\VarDumper\Tests\Test;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Test\VarDumperTestTrait;
class VarDumperTestTraitTest extends \PHPUnit_Framework_TestCase
class VarDumperTestTraitTest extends TestCase
{
use VarDumperTestTrait;
use VarDumperTestTrait;
public function testItComparesLargeData()
{
$howMany = 700;
$data = array_fill_keys(range(0, $howMany), array('a', 'b', 'c', 'd'));
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
$expected = sprintf("array:%d [\n", $howMany + 1);
for ($i = 0; $i <= $howMany; ++$i) {
$expected .= <<<EODUMP
$i => array:4 [
0 => "a"
1 => "b"
@ -32,9 +33,9 @@ class VarDumperTestTraitTest extends \PHPUnit_Framework_TestCase
3 => "d"
]\n
EODUMP;
}
$expected .= "]\n";
}
$expected .= "]\n";
$this->assertDumpEquals($expected, $data);
}
$this->assertDumpEquals($expected, $data);
}
}

View File

@ -11,21 +11,22 @@
namespace Symfony\Component\VarDumper\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\VarDumper\Cloner\VarCloner;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class VarClonerTest extends \PHPUnit_Framework_TestCase
class VarClonerTest extends TestCase
{
public function testMaxIntBoundary()
{
$data = array(PHP_INT_MAX => 123);
public function testMaxIntBoundary()
{
$data = array(PHP_INT_MAX => 123);
$cloner = new VarCloner();
$clone = $cloner->cloneVar($data);
$cloner = new VarCloner();
$clone = $cloner->cloneVar($data);
$expected = <<<EOTXT
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
@ -41,6 +42,10 @@ Symfony\Component\VarDumper\Cloner\Data Object
[handle] => 0
[refCount] => 0
[position] => 1
[attr] => Array
(
)
)
)
@ -52,23 +57,25 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[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));
}
$this->assertSame(sprintf($expected, PHP_INT_MAX), print_r($clone, true));
}
public function testClone()
{
$json = json_decode('{"1":{"var":"val"},"2":{"var":"val"}}');
public function testClone()
{
$json = json_decode('{"1":{"var":"val"},"2":{"var":"val"}}');
$cloner = new VarCloner();
$clone = $cloner->cloneVar($json);
$cloner = new VarCloner();
$clone = $cloner->cloneVar($json);
$expected = <<<EOTXT
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
@ -84,6 +91,10 @@ Symfony\Component\VarDumper\Cloner\Data Object
[handle] => %i
[refCount] => 0
[position] => 1
[attr] => Array
(
)
)
)
@ -99,6 +110,10 @@ Symfony\Component\VarDumper\Cloner\Data Object
[handle] => %i
[refCount] => 0
[position] => 2
[attr] => Array
(
)
)
[\000+\0002] => Symfony\Component\VarDumper\Cloner\Stub Object
@ -110,6 +125,10 @@ Symfony\Component\VarDumper\Cloner\Data Object
[handle] => %i
[refCount] => 0
[position] => 3
[attr] => Array
(
)
)
)
@ -126,30 +145,112 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[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));
$this->assertStringMatchesFormat($expected, print_r($clone, true));
}
public function testJsonCast()
{
if (ini_get('xdebug.overload_var_dump') == 2) {
$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]=>
object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) {
["type"]=>
string(5) "array"
["class"]=>
string(5) "assoc"
["value"]=>
int(1)
["cut"]=>
int(0)
["handle"]=>
int(0)
["refCount"]=>
int(0)
["position"]=>
int(1)
["attr"]=>
array(0) {
}
}
}
[1]=>
array(1) {
["1"]=>
object(Symfony\Component\VarDumper\Cloner\Stub)#%i (8) {
["type"]=>
string(6) "object"
["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)
}
public function testCaster()
{
$cloner = new VarCloner(array(
'*' => function ($obj, $array) {
return array('foo' => 123);
},
__CLASS__ => function ($obj, $array) {
++$array['foo'];
EOTXT;
ob_start();
var_dump($clone);
$this->assertStringMatchesFormat(\PHP_VERSION_ID >= 70200 ? str_replace('"1"', '1', $expected) : $expected, ob_get_clean());
}
return $array;
},
));
$clone = $cloner->cloneVar($this);
public function testCaster()
{
$cloner = new VarCloner(array(
'*' => function ($obj, $array) {
return array('foo' => 123);
},
__CLASS__ => function ($obj, $array) {
++$array['foo'];
$expected = <<<EOTXT
return $array;
},
));
$clone = $cloner->cloneVar($this);
$expected = <<<EOTXT
Symfony\Component\VarDumper\Cloner\Data Object
(
[data:Symfony\Component\VarDumper\Cloner\Data:private] => Array
@ -165,6 +266,10 @@ Symfony\Component\VarDumper\Cloner\Data Object
[handle] => %i
[refCount] => 0
[position] => 1
[attr] => Array
(
)
)
)
@ -176,12 +281,14 @@ Symfony\Component\VarDumper\Cloner\Data Object
)
[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));
}
$this->assertStringMatchesFormat($expected, print_r($clone, true));
}
}

View File

@ -20,9 +20,14 @@
"symfony/polyfill-mbstring": "~1.0"
},
"require-dev": {
"twig/twig": "~1.20|~2.0"
"ext-iconv": "*",
"twig/twig": "~1.34|~2.4"
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
},
"suggest": {
"ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
"ext-symfony_debug": ""
},
"autoload": {
@ -35,7 +40,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "3.2-dev"
}
}
}

View File

@ -5,9 +5,13 @@
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>