Thanks to visit codestin.com
Credit goes to github.com

Skip to content

ReflectionExtractor::getTypes prioritizes unreliable sources to determine the type #57719

Open
@skobkin

Description

@skobkin

Symfony version(s) affected

<= 6.4 =>

Still present in latest stable release.

Description

Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor::getTypes gives more priority to accessor and/or mutator methods over constructor definition even when it uses type hinting.

ReflectionExtractor:

public function getTypes(string $class, string $property, array $context = []): ?array
{
    if ($fromMutator = $this->extractFromMutator($class, $property)) {
        return $fromMutator;
    }
    if ($fromAccessor = $this->extractFromAccessor($class, $property)) {
        return $fromAccessor; // data suggesting 'bool' returned before extracting from constructor
    }
    if (
        ($context['enable_constructor_extraction'] ?? $this->enableConstructorExtraction)
        && $fromConstructor = $this->extractFromConstructor($class, $property)
    ) {
        return $fromConstructor;
    }
    if ($fromPropertyDeclaration = $this->extractFromPropertyDeclaration($class, $property)) {
        return $fromPropertyDeclaration;
    }
    return null;
}

How to reproduce

The problem could be reproduced for example when using Symfony Serializer:

We define a class which instantiates it's properties in the constructor and uses type hints there. We also add some method which could be classified as accessor or mutator by ReflectionExtractor:

class SomeResponse
{
    public function __construct(
        #[SerializedName('url')]
        public readonly ?string $url, // this type hint is ignored
    ) {
    }

    public function hasUrl(): bool // type is being detected from here
    {
        return !empty($this->url);
    }
}

Now we try to deserialize simple JSON:

$serializer->deserialize(SomeResponse::class, '{"url": "http://test"}');

We'll get this error in the exception:

The type of the "url" attribute for class "SomeResponse" must be one of "bool" ("string" given).

Possible Solution

Maybe check if we can detect the type from constructor and if so, use it as a more reliable source.

Additional Context

No response

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