diff --git a/Normalizer/ObjectNormalizer.php b/Normalizer/ObjectNormalizer.php index 158fa9d5d..53c1e4cb1 100644 --- a/Normalizer/ObjectNormalizer.php +++ b/Normalizer/ObjectNormalizer.php @@ -107,23 +107,17 @@ protected function extractAttributes(object $object, string $format = null, arra } } - $checkPropertyInitialization = \PHP_VERSION_ID >= 70400; - // properties + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; foreach ($reflClass->getProperties() as $reflProperty) { - $isPublic = $reflProperty->isPublic(); - - if ($checkPropertyInitialization) { - if (!$isPublic) { - $reflProperty->setAccessible(true); - } - if (!$reflProperty->isInitialized($object)) { + if (null !== $propertyValues && !\array_key_exists($reflProperty->name, $propertyValues)) { + if ($reflProperty->isPublic() + || ($reflProperty->isProtected() && !\array_key_exists("\0*\0{$reflProperty->name}", $propertyValues)) + || ($reflProperty->isPrivate() && !\array_key_exists("\0{$reflProperty->class}\0{$reflProperty->name}", $propertyValues)) + ) { unset($attributes[$reflProperty->name]); - continue; } - } - if (!$isPublic) { continue; } diff --git a/Normalizer/PropertyNormalizer.php b/Normalizer/PropertyNormalizer.php index 39e750275..7c333059a 100644 --- a/Normalizer/PropertyNormalizer.php +++ b/Normalizer/PropertyNormalizer.php @@ -101,21 +101,17 @@ protected function extractAttributes(object $object, string $format = null, arra { $reflectionObject = new \ReflectionObject($object); $attributes = []; - $checkPropertyInitialization = \PHP_VERSION_ID >= 70400; + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; do { foreach ($reflectionObject->getProperties() as $property) { - if ($checkPropertyInitialization) { - if (!$property->isPublic()) { - $property->setAccessible(true); - } - - if (!$property->isInitialized($object)) { - continue; - } - } - - if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) { + if ((null !== $propertyValues && ( + ($property->isPublic() && !\array_key_exists($property->name, $propertyValues)) + || ($property->isProtected() && !\array_key_exists("\0*\0{$property->name}", $propertyValues)) + || ($property->isPrivate() && !\array_key_exists("\0{$property->class}\0{$property->name}", $propertyValues)) + )) + || !$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context) + ) { continue; } @@ -123,7 +119,7 @@ protected function extractAttributes(object $object, string $format = null, arra } } while ($reflectionObject = $reflectionObject->getParentClass()); - return $attributes; + return array_unique($attributes); } /** diff --git a/Tests/Normalizer/ObjectNormalizerTest.php b/Tests/Normalizer/ObjectNormalizerTest.php index ec9261991..d60571307 100644 --- a/Tests/Normalizer/ObjectNormalizerTest.php +++ b/Tests/Normalizer/ObjectNormalizerTest.php @@ -131,6 +131,26 @@ public function testNormalizeObjectWithUninitializedProperties() ); } + public function testNormalizeObjectWithUnsetProperties() + { + $obj = new ObjectInner(); + unset($obj->foo); + $this->assertEquals( + ['bar' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testNormalizeObjectWithLazyProperties() + { + $obj = new LazyObjectInner(); + unset($obj->foo); + $this->assertEquals( + ['foo' => 123, 'bar' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + /** * @requires PHP 7.4 */ @@ -928,6 +948,16 @@ class ObjectInner public $bar; } +class LazyObjectInner extends ObjectInner +{ + public function __get($name) + { + if ('foo' === $name) { + return $this->foo = 123; + } + } +} + class FormatAndContextAwareNormalizer extends ObjectNormalizer { protected function isAllowedAttribute($classOrObject, string $attribute, string $format = null, array $context = []): bool diff --git a/Tests/Normalizer/PropertyNormalizerTest.php b/Tests/Normalizer/PropertyNormalizerTest.php index 519d42ff2..c8cfcd3c2 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -98,6 +98,26 @@ public function testNormalizeObjectWithUninitializedProperties() ); } + public function testNormalizeObjectWithUnsetProperties() + { + $obj = new PropertyDummy(); + unset($obj->foo); + $this->assertEquals( + ['bar' => null, 'camelCase' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + + public function testNormalizeObjectWithLazyProperties() + { + $obj = new LazyPropertyDummy(); + unset($obj->foo); + $this->assertEquals( + ['foo' => 123, 'bar' => null, 'camelCase' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + public function testDenormalize() { $obj = $this->normalizer->denormalize( @@ -431,6 +451,16 @@ public function setCamelCase($camelCase) } } +class LazyPropertyDummy extends PropertyDummy +{ + public function __get($name) + { + if ('foo' === $name) { + return $this->foo = 123; + } + } +} + class PropertyConstructorDummy { protected $foo;
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: