bug #14852 [VarDumper] Fix generic casters calling order (nicolas-grekas)

This PR was merged into the 2.7 branch.

Discussion
----------

[VarDumper] Fix generic casters calling order

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

There is a logical mistake in the calling order of the catch all `*` caster. Casters are called with increasing specificity, from parents first to children classes last. But this one is currently called last, although it is the less specific. Here is the fix in `AbstractCloner`.
All the other changes are adding robustness to potentially not-set array indexes.

Commits
-------

ec124e0 [VarDumper] Fix generic casters calling order
This commit is contained in:
Fabien Potencier 2015-06-04 16:40:31 +02:00
commit d6b0e64a5d
4 changed files with 31 additions and 26 deletions

View File

@ -25,34 +25,35 @@ class DoctrineCaster
{
public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested)
{
unset(
$a['__cloner__'],
$a['__initializer__']
);
$stub->cut += 2;
foreach (array('__cloner__', '__initializer__') as $k) {
if (array_key_exists($k, $a)) {
unset($a[$k]);
++$stub->cut;
}
}
return $a;
}
public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested)
{
$prefix = "\0Doctrine\\ORM\\Proxy\\Proxy\0";
unset(
$a[$prefix.'_entityPersister'],
$a[$prefix.'_identifier']
);
$stub->cut += 2;
foreach (array('_entityPersister', '_identifier') as $k) {
if (array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) {
unset($a[$k]);
++$stub->cut;
}
}
return $a;
}
public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested)
{
$prefix = "\0Doctrine\\ORM\\PersistentCollection\0";
$a[$prefix.'snapshot'] = new CutStub($a[$prefix.'snapshot']);
$a[$prefix.'association'] = new CutStub($a[$prefix.'association']);
$a[$prefix.'typeClass'] = new CutStub($a[$prefix.'typeClass']);
foreach (array('snapshot', 'association', 'typeClass') as $k) {
if (array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) {
$a[$k] = new CutStub($a[$k]);
}
}
return $a;
}

View File

@ -43,8 +43,12 @@ class ExceptionCaster
public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
{
$xPrefix = PHP_VERSION_ID >= 70000 ? "\0BaseException\0" : "\0Exception\0";
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
if (isset($a[$xPrefix.'trace'])) {
$trace = $a[$xPrefix.'trace'];
unset($a[$xPrefix.'trace']); // Ensures the trace is always last
} else {
$trace = array();
}
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
static::filterTrace($trace, static::$traceArgs);
@ -74,9 +78,9 @@ class ExceptionCaster
{
$prefix = Caster::PREFIX_PROTECTED;
$xPrefix = PHP_VERSION_ID >= 70000 ? "\0BaseException\0" : "\0Exception\0";
$b = (array) $a[$xPrefix.'previous'];
if (isset($a[$xPrefix.'trace'][0])) {
if (isset($a[$xPrefix.'previous'], $a[$xPrefix.'trace'][0])) {
$b = (array) $a[$xPrefix.'previous'];
$b[$xPrefix.'trace'][0] += array(
'file' => $b[$prefix.'file'],
'line' => $b[$prefix.'line'],

View File

@ -214,7 +214,7 @@ abstract class AbstractCloner implements ClonerInterface
$classInfo = array(
$class,
new \ReflectionClass($class),
array_reverse(array('*' => '*', $class => $class) + class_parents($class) + class_implements($class)),
array_reverse(array($class => $class) + class_parents($class) + class_implements($class) + array('*' => '*')),
);
$this->classInfo[$class] = $classInfo;

View File

@ -139,12 +139,12 @@ EOTXT;
{
$cloner = new VarCloner(array(
'*' => function ($obj, $array) {
$array['foo'] = 123;
return $array;
return array('foo' => 123);
},
__CLASS__ => function ($obj, $array) {
return array();
++$array['foo'];
return $array;
},
));
$clone = $cloner->cloneVar($this);
@ -171,7 +171,7 @@ Symfony\Component\VarDumper\Cloner\Data Object
[1] => Array
(
[foo] => 123
[foo] => 124
)
)