8000 [VarDumper] Add filters to casters by nicolas-grekas · Pull Request #14058 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[VarDumper] Add filters to casters #14058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 30, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions src/Symfony/Component/VarDumper/Caster/Caster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?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;

/**
* Helper for filtering out properties in casters.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add some phpdoc to explain the meaning of some of these flags. Most of them are understandable from their name, but EXCLUDE_NOT_IMPORTANT, EXCLUDE_VERBOSE and EXCLUDE_STRICT might deserve some explanations

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments added in the method doc block. Good enough for you?


/**
* 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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this method actually used anywhere ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in Symfony but I hope to use it in PsySH bobthecow/psysh#184

{
foreach ($a as $k => $v) {
$type = self::EXCLUDE_STRICT & $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 (!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 ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) {
unset($a[$k]);
}
}

return $a;
}
}
10 changes: 6 additions & 4 deletions src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,17 @@ class ExceptionCaster
E_STRICT => 'E_STRICT',
);

public static function castException(\Exception $e, array $a, Stub $stub, $isNested)
public static function castException(\Exception $e, array $a, Stub $stub, $isNested, $filter = 0)
{
$trace = $a["\0Exception\0trace"];
unset($a["\0Exception\0trace"]); // Ensures the trace is always last

static::filterTrace($trace, static::$traceArgs);
if (!($filter & Caster::EXCLUDE_VERBOSE)) {
static::filterTrace($trace, static::$traceArgs);

if (null !== $trace) {
$a["\0Exception\0trace"] = $trace;
if (null !== $trace) {
$a["\0Exception\0trace"] = $trace;
}
}
if (empty($a["\0Exception\0previous"])) {
unset($a["\0Exception\0previous"]);
Expand Down
13 changes: 10 additions & 3 deletions src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ abstract class AbstractCloner implements ClonerInterface
private $casters = array();
private $prevErrorHandler;
private $classInfo = array();
private $filter = 0;

/**
* @param callable[]|null $casters A map of casters.
Expand Down Expand Up @@ -149,10 +150,16 @@ public function setMaxString($maxString)
}

/**
* {@inheritdoc}
* 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)
public function cloneVar($var, $filter = 0)
{
$this->filter = $filter;
$this->prevErrorHandler = set_error_handler(array($this, 'handleError'));
try {
if (!function_exists('iconv')) {
Expand Down Expand Up @@ -270,7 +277,7 @@ protected function castResource(Stub $stub, $isNested)
private function callCaster($callback, $obj, $a, $stub, $isNested)
{
try {
$cast = call_user_func($callback, $obj, $a, $stub, $isNested);
$cast = call_user_func($callback, $obj, $a, $stub, $isNested, $this->filter);

if (is_array($cast)) {
$a = $cast;
Expand Down
147 changes: 147 additions & 0 deletions src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?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 Symfony\Component\VarDumper\Caster\Caster;

/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class CasterTest extends \PHPUnit_Framework_TestCase
{
private $referenceArray = array(
'null' => null,
'empty' => false,
'public' => 'pub',
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0*\0protected" => 'prot',
"\0Foo\0private" => 'priv',
);

/** @dataProvider provideFilter */
public function testFilter($filter, $expectedDiff, $listedProperties = null)
{
if (null === $listedProperties) {
$filteredArray = Caster::filter($this->referenceArray, $filter);
} else {
$filteredArray = Caster::filter($this->referenceArray, $filter, $listedProperties);
}

$this->assertSame($expectedDiff, array_diff_assoc($this->referenceArray, $filteredArray));
}

public function provideFilter()
{
return array(
array(
0,
array(),
),
array(
Caster::EXCLUDE_PUBLIC,
array(
'null' => null,
'empty' => false,
'public' => 'pub',
),
),
array(
Caster::EXCLUDE_NULL,
array(
'null' => null,
),
),
array(
Caster::EXCLUDE_EMPTY,
array(
'null' => null,
'empty' => false,
),
),
array(
Caster::EXCLUDE_VIRTUAL,
array(
"\0~\0virtual" => 'virt',
),
),
array(
Caster::EXCLUDE_DYNAMIC,
array(
"\0+\0dynamic" => 'dyn',
),
),
array(
Caster::EXCLUDE_PROTECTED,
array(
"\0*\0protected" => 'prot',
),
),
array(
Caster::EXCLUDE_PRIVATE,
array(
"\0Foo\0private" => 'priv',
),
),
array(
Caster::EXCLUDE_VERBOSE,
array(
'public' => 'pub',
"\0*\0protected" => 'prot',
),
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT,
array(
'null' => null,
'empty' => false,
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
"\0Foo\0private" => 'priv',
),
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_VIRTUAL | Caster::EXCLUDE_DYNAMIC,
array(
"\0~\0virtual" => 'virt',
"\0+\0dynamic" => 'dyn',
),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_VERBOSE,
$this->referenceArray,
array('public', "\0*\0protected"),
),
array(
Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_EMPTY,
array(
'null' => null,
5F83 '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'),
),
);
}
}
0