Skip to content

[PropertyInfo] Bug - Nullable typehints with default value are processed incorrectly #40659

Closed
@maxim-dovydenok

Description

@maxim-dovydenok

Symfony version(s) affected: 5.2.4

Description
When I get types of nullable property with default value using ReflectionExtractor, I get that this value is not nullable.

How to reproduce

class Test {
    public ?string $nullableWithoutDefault;
    public ?string $nullableWithDefault = 'default';
    public string $withoutDefault;
    public string $withDefault = 'default';
}

$extractor = new ReflectionExtractor();

dump($extractor->getTypes(Test::class, 'nullableWithoutDefault'));
dump($extractor->getTypes(Test::class, 'nullableWithDefault'));
dump($extractor->getTypes(Test::class, 'withoutDefault'));
dump($extractor->getTypes(Test::class, 'withDefault'));

Output:

array:1 [
  0 => Symfony\Component\PropertyInfo\Type^ {#1530
    -builtinType: "string"
    -nullable: true
    -class: null
    -collection: false
    -collectionKeyType: null
    -collectionValueType: null
  }
]

array:1 [
  0 => Symfony\Component\PropertyInfo\Type^ {#1534
    -builtinType: "string"
    -nullable: false                            <----- I expect true here
    -class: null
    -collection: false
    -collectionKeyType: null
    -collectionValueType: null
  }
]

array:1 [
  0 => Symfony\Component\PropertyInfo\Type^ {#1537
    -builtinType: "string"
    -nullable: false
    -class: null
    -collection: false
    -collectionKeyType: null
    -collectionValueType: null
  }
]

array:1 [
  0 => Symfony\Component\PropertyInfo\Type^ {#1541
    -builtinType: "string"
    -nullable: false
    -class: null
    -collection: false
    -collectionKeyType: null
    -collectionValueType: null
  }
]

Possible Solution
In ReflectionExtractor class, extractFromDefaultValue is above extractFromReflectionType, perhaps we should use isNullable from the typehint?

It was introduced in #38041

Current version:

        if ($fromDefaultValue = $this->extractFromDefaultValue($class, $property)) {
            return $fromDefaultValue;
        }

        if (\PHP_VERSION_ID >= 70400) {
            try {
                $reflectionProperty = new \ReflectionProperty($class, $property);
                $type = $reflectionProperty->getType();
                if (null !== $type && $types = $this->extractFromReflectionType($type, $reflectionProperty->getDeclaringClass())) {
                    return $types;
                }
            } catch (\ReflectionException $e) {
                // noop
            }
        }

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