From 768c3e563f36eb5aa6f6717f42bc1e3c41b901de Mon Sep 17 00:00:00 2001 From: bkrukowski Date: Sat, 21 Apr 2018 02:48:41 +0200 Subject: [PATCH] 1) Use get_object_vars instead of ReflectionObject::getProperties whenever object contains method __get 2) In some cases method "dump" didn't work properly, because the following code triggers "Notice: Undefined property: Foo::$a", fixed issue: class Foo { private $a = 'a'; public function __construct() { unset($this->a); } } $obj = new Foo(); $reflectionObj = new ReflectionObject($obj); $reflectionProp = $reflectionObj->getProperty('a'); $reflectionProp->setAccessible(true); $reflectionProp->getValue($obj); --- src/Properties/AbstractProperties.php | 29 +++++++- tests/MagicMethods/GetterObject.php | 25 +++++++ tests/MagicMethods/MagicMethodsTest.php | 88 +++++++++++++++++++++++++ tests/MagicMethods/RemovedProperty.php | 51 ++++++++++++++ 4 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 tests/MagicMethods/GetterObject.php create mode 100644 tests/MagicMethods/MagicMethodsTest.php create mode 100644 tests/MagicMethods/RemovedProperty.php diff --git a/src/Properties/AbstractProperties.php b/src/Properties/AbstractProperties.php index b13f3ee..332a435 100644 --- a/src/Properties/AbstractProperties.php +++ b/src/Properties/AbstractProperties.php @@ -21,7 +21,34 @@ abstract class AbstractProperties implements PropertiesInterface protected function getDeclaredProperties() { $reflection = new \ReflectionObject($this->object); + $result = array(); - return $reflection->getProperties(); + if ($reflection->hasMethod('__get')) { + foreach (\array_keys(\get_object_vars($this->object)) as $name) { + $result[] = $reflection->getProperty($name); + } + + return $result; + } + + foreach ($reflection->getProperties() as $property) { + $continue = false; + \set_error_handler( + function () use (&$continue) { + $continue = true; + }, + E_NOTICE + ); + $property->setAccessible(true); + $property->getValue($this->object); + \restore_error_handler(); + if ($continue) { + continue; + } + + $result[] = $property; + } + + return $result; } } diff --git a/tests/MagicMethods/GetterObject.php b/tests/MagicMethods/GetterObject.php new file mode 100644 index 0000000..a3bcbd7 --- /dev/null +++ b/tests/MagicMethods/GetterObject.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Awesomite\VarDumper\MagicMethods; + +/** + * @internal + */ +class GetterObject extends RemovedProperty +{ + private $c = 'c'; + + public function __get($name) + { + return $this->$name; + } +} diff --git a/tests/MagicMethods/MagicMethodsTest.php b/tests/MagicMethods/MagicMethodsTest.php new file mode 100644 index 0000000..91e4a61 --- /dev/null +++ b/tests/MagicMethods/MagicMethodsTest.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Awesomite\VarDumper\MagicMethods; + +use Awesomite\VarDumper\BaseTestCase; +use Awesomite\VarDumper\LightVarDumper; +use Awesomite\VarDumper\Properties\Properties; +use Awesomite\VarDumper\Properties\PropertyInterface; + +/** + * @internal + */ +class MagicMethodsTest extends BaseTestCase +{ + public function testDump() + { + $dumper = new LightVarDumper(); + $object = new RemovedProperty(); + + $expected + = <<<'EXPECTED' +(2) { + private $a => “a” + private $b => “b” +} +EXPECTED; + $this->assertContains($expected, $dumper->dumpAsString($object)); + + $object->without('a'); + $expected + = <<<'EXPECTED' +(1) { + private $b => “b” +} +EXPECTED; + $this->assertContains($expected, $dumper->dumpAsString($object)); + + $object->c = 'c'; + $expected + = <<<'EXPECTED' +(2) { + private $b => “b” + $c => “c” +} +EXPECTED; + $this->assertContains($expected, $dumper->dumpAsString($object)); + + $getter = new GetterObject(); + $this->assertContains('(0) {}', $dumper->dumpAsString($getter)); + } + + /** + * @dataProvider providerAbstractProperties + * + * @param $object + * @param string[] $expectedProperties + */ + public function testAbstractProperties($object, array $expectedProperties) + { + $reader = new Properties($object); + + $this->assertSame(\count($expectedProperties), \count($reader->getProperties())); + foreach ($reader->getProperties() as $property) { + /** @var PropertyInterface $property */ + $this->assertContains($property->getName(), $expectedProperties); + } + } + + public function providerAbstractProperties() + { + return array( + array(new RemovedProperty(), array('a', 'b')), + array(new GetterObject(), array()), + array(RemovedProperty::createWithout(array('a')), array('b')), + array(RemovedProperty::createWithout(array('a'))->with('c'), array('b', 'c')), + array(RemovedProperty::createWithout(array('a', 'b')), array()), + ); + } +} diff --git a/tests/MagicMethods/RemovedProperty.php b/tests/MagicMethods/RemovedProperty.php new file mode 100644 index 0000000..7c57c4e --- /dev/null +++ b/tests/MagicMethods/RemovedProperty.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Awesomite\VarDumper\MagicMethods; + +/** + * @internal + */ +class RemovedProperty +{ + private $a = 'a'; + + private $b = 'b'; + + public function without($name) + { + unset($this->$name); + + return $this; + } + + public function with($name, $value = null) + { + $this->$name = $value; + + return $this; + } + + /** + * @param string[] $props + * + * @return static + */ + public static function createWithout(array $props) + { + $result = new static(); + foreach ($props as $prop) { + $result->without($prop); + } + + return $result; + } +}