Skip to content

[Serializer] Only unset data in AbstractNormalizer::instantiateObject if constructor invocation succeeded #52499

Closed
@philipsorst

Description

@philipsorst

Symfony version(s) affected

6.3.x,5.4.x

Description

The AbstractNormalizer::instantiateObject unsets the corresponding &$data value for a constructor argument if it believes it will be set by constructor invocation so that no set is called later on. However, if constructor invocation fails as it is missing arguments, the value won't be set again at a later stage, even if the object could be instantiated partially when setting the property later on.

How to reproduce

If we have an example object

class ExampleObject
{
    public function __construct(public readonly string $propertyMissing, public readonly string $propertyGiven)
    {
    }
}

I would expect the following test to pass:

try {
    $exampleObject = $serializer->denormalize(['propertyGiven' => 'foo'],
        ExampleObject::class,
        null,
        [DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true]);
} catch (PartialDenormalizationException $e) {
    $exampleObject = $e->getData();
}
self::assertInstanceOf(ExampleObject::class, $exampleObject);
self::assertEquals('foo', $exampleObject->propertyGiven);

however it says: $propertyGiven must not be accessed before initialization as there was no attempt to set it later on after the constructor instantiation failed.

Possible Solution

Remember the properties that have to be unset if the constructor instantiation succeeds and only unset them if there are no missing parameters and the instantiation actually worked.

Additional Context

I realized this as the behaviour changed with commit c54cfbb6f3129c41ea5b26b4e3115919132ab726 as it now collects all missing arguments. Before it returned early and the $data values for later constructor arguments were not unset. So this is kind of a regression, although before it just worked "accidentially" in my use case as the first argument was already missing for my data.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions