diff --git a/Normalizer/ObjectNormalizer.php b/Normalizer/ObjectNormalizer.php index a8bf91899..53c1e4cb1 100644 --- a/Normalizer/ObjectNormalizer.php +++ b/Normalizer/ObjectNormalizer.php @@ -108,9 +108,9 @@ protected function extractAttributes(object $object, string $format = null, arra } // properties - $propertyValues = (array) $object; + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; foreach ($reflClass->getProperties() as $reflProperty) { - if (!\array_key_exists($reflProperty->name, $propertyValues)) { + 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)) diff --git a/Normalizer/PropertyNormalizer.php b/Normalizer/PropertyNormalizer.php index fffbc2030..fb0d29564 100644 --- a/Normalizer/PropertyNormalizer.php +++ b/Normalizer/PropertyNormalizer.php @@ -101,13 +101,15 @@ protected function extractAttributes(object $object, string $format = null, arra { $reflectionObject = new \ReflectionObject($object); $attributes = []; - $propertyValues = (array) $object; + $propertyValues = !method_exists($object, '__get') ? (array) $object : null; do { foreach ($reflectionObject->getProperties() as $property) { - if (($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)) + 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; diff --git a/Tests/Normalizer/ObjectNormalizerTest.php b/Tests/Normalizer/ObjectNormalizerTest.php index c34fa20b6..d60571307 100644 --- a/Tests/Normalizer/ObjectNormalizerTest.php +++ b/Tests/Normalizer/ObjectNormalizerTest.php @@ -141,6 +141,16 @@ public function testNormalizeObjectWithUnsetProperties() ); } + public function testNormalizeObjectWithLazyProperties() + { + $obj = new LazyObjectInner(); + unset($obj->foo); + $this->assertEquals( + ['foo' => 123, 'bar' => null], + $this->normalizer->normalize($obj, 'any') + ); + } + /** * @requires PHP 7.4 */ @@ -938,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 98e0cb497..c8cfcd3c2 100644 --- a/Tests/Normalizer/PropertyNormalizerTest.php +++ b/Tests/Normalizer/PropertyNormalizerTest.php @@ -108,6 +108,16 @@ public function testNormalizeObjectWithUnsetProperties() ); } + 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( @@ -441,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;