Skip to content
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

[Serializer] Add support for extending stdClass objects #54613

Open
template-provider opened this issue Apr 16, 2024 · 3 comments
Open

[Serializer] Add support for extending stdClass objects #54613

template-provider opened this issue Apr 16, 2024 · 3 comments

Comments

@template-provider
Copy link

Symfony version(s) affected

6.4

Description

The serialize and unserialize for stdClass works because of this code in the class ObjectNormalizer + method extractAttributes

        if (\stdClass::class === $object::class) {
            return array_keys((array) $object);
        }

but this code does not check for classes, that are extending stdClass.

How to reproduce

<?php

declare(strict_types = 1);

use stdClass;

class Contact extends stdClass
{
    public string $email = '';
}
        $encoders = [new JsonEncoder()];

        $classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
        $metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
        $extractor = new PropertyInfoExtractor([], [new PhpDocExtractor(), new ReflectionExtractor()]);

        $objectNormalizer =  new ObjectNormalizer(
            classMetadataFactory: $classMetadataFactory,
            nameConverter: $metadataAwareNameConverter,
            propertyTypeExtractor: $extractor,
            defaultContext: [
                AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES => true,
                AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
                AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT => true,
            ],
        );

        $normalizers = [
            $objectNormalizer,
        ];

        $serializer = new Serializer($normalizers, $encoders)

$contact = new Contact();
$contact->email = 'foo@example.com';
$contact->foo = 'bar';

$serializer->serialize($contact, 'json')

Possible Solution

Better would be some additional code like this:

        $classParents = class_parents($object::class);
        if (false !== $classParents && in_array(\stdClass::class, $classParents)) {
            return array_keys((array) $object);
        }

Additional Context

No response

@alexandre-daubois
Copy link
Contributor

What about classes extending stdClass and also defining other properties, public or not, with getters/setters? Just casting the object with as it is done with stdClass wouldn't fully work, isn't it?

@template-provider
Copy link
Author

I am not 100 percent sure what you mean. A getter/setter does not change anything for unknown properties during serialize/unserialize. The only possible solution would be magic getters/setters to set the unknown property.
But I have not tested it yet and do not even know if symfony serializer works with __get and __set.
Could you provide an example what you mean plz?

@template-provider
Copy link
Author

And as described above the problem is in unserialize to. In this case the following lines:
https://github.com/symfony/property-access/blob/7.0/PropertyAccessor.php#L525

            } elseif ($object instanceof \stdClass && property_exists($object, $property)) {
                $object->$property = $value;
            } elseif (!$this->ignoreInvalidProperty) {

The property_exists might not be needed imho. "} elseif ($object instanceof \stdClass) {" works

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants