From 92b0da17f9d1fcbd148d8548d861b8b8cb0eb0fa Mon Sep 17 00:00:00 2001 From: rvoisin Date: Tue, 18 Jan 2022 14:06:28 +0100 Subject: [PATCH] [PropertyInfo] Add PHP 8.0 promoted properties `@param` mutation support to `PhpDocExtractor` --- .../Component/PropertyInfo/CHANGELOG.md | 1 + .../Extractor/PhpDocExtractor.php | 28 ++++++++++--------- .../Tests/Extractor/PhpDocExtractorTest.php | 17 +++++++++++ .../Tests/Fixtures/Php80Dummy.php | 7 +++++ 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/CHANGELOG.md b/src/Symfony/Component/PropertyInfo/CHANGELOG.md index 0970592546afa..6d408eb87e39a 100644 --- a/src/Symfony/Component/PropertyInfo/CHANGELOG.md +++ b/src/Symfony/Component/PropertyInfo/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG --- * Add support for phpDocumentor and PHPStan pseudo-types + * Add PHP 8.0 promoted properties `@param` mutation support to `PhpDocExtractor` 6.0 --- diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index b414330b5a247..f3827e44f393c 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -128,19 +128,11 @@ public function getTypes(string $class, string $property, array $context = []): return null; } - switch ($source) { - case self::PROPERTY: - $tag = 'var'; - break; - - case self::ACCESSOR: - $tag = 'return'; - break; - - case self::MUTATOR: - $tag = 'param'; - break; - } + $tag = match ($source) { + self::PROPERTY => 'var', + self::ACCESSOR => 'return', + self::MUTATOR => 'param', + }; $parentClass = null; $types = []; @@ -249,9 +241,19 @@ private function getDocBlock(string $class, string $property): array return $this->docBlocks[$propertyHash]; } + try { + $reflectionProperty = new \ReflectionProperty($class, $property); + } catch (\ReflectionException $e) { + $reflectionProperty = null; + } + $ucFirstProperty = ucfirst($property); switch (true) { + case $reflectionProperty?->isPromoted() && $docBlock = $this->getDocBlockFromConstructor($class, $property): + $data = [$docBlock, self::MUTATOR, null]; + break; + case $docBlock = $this->getDocBlockFromProperty($class, $property): $data = [$docBlock, self::PROPERTY, null]; break; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index ba93cf47a8055..ce406500c3cb5 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -16,6 +16,7 @@ use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy; +use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; use Symfony\Component\PropertyInfo\Type; @@ -429,6 +430,22 @@ public function pseudoTypesProvider(): array ['positiveInt', [new Type(Type::BUILTIN_TYPE_INT, false, null)]], ]; } + + /** + * @dataProvider promotedPropertyProvider + */ + public function testExtractPromotedProperty(string $property, ?array $types) + { + $this->assertEquals($types, $this->extractor->getTypes(Php80Dummy::class, $property)); + } + + public function promotedPropertyProvider(): array + { + return [ + ['promoted', null], + ['promotedAndMutated', [new Type(Type::BUILTIN_TYPE_STRING)]], + ]; + } } class EmptyDocBlock diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php index e8eac72be8df0..bf97804e56e22 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php @@ -6,6 +6,13 @@ class Php80Dummy { public mixed $mixedProperty; + /** + * @param string $promotedAndMutated + */ + public function __construct(private mixed $promoted, private mixed $promotedAndMutated) + { + } + public function getFoo(): array|null { }