diff --git a/src/Symfony/Component/PropertyInfo/CHANGELOG.md b/src/Symfony/Component/PropertyInfo/CHANGELOG.md index 6d408eb87e39..3595f75017c6 100644 --- a/src/Symfony/Component/PropertyInfo/CHANGELOG.md +++ b/src/Symfony/Component/PropertyInfo/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Add support for phpDocumentor and PHPStan pseudo-types * Add PHP 8.0 promoted properties `@param` mutation support to `PhpDocExtractor` + * Add PHP 8.0 promoted properties `@param` mutation support to `PhpStanExtractor` 6.0 --- diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php index 89721f4e666a..db25e14f4473 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpStanExtractor.php @@ -196,8 +196,8 @@ private function getDocBlock(string $class, string $property): array $ucFirstProperty = ucfirst($property); - if ([$docBlock, $declaringClass] = $this->getDocBlockFromProperty($class, $property)) { - $data = [$docBlock, self::PROPERTY, null, $declaringClass]; + if ([$docBlock, $source, $declaringClass] = $this->getDocBlockFromProperty($class, $property)) { + $data = [$docBlock, $source, null, $declaringClass]; } elseif ([$docBlock, $_, $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR)) { $data = [$docBlock, self::ACCESSOR, null, $declaringClass]; } elseif ([$docBlock, $prefix, $declaringClass] = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR)) { @@ -210,7 +210,7 @@ private function getDocBlock(string $class, string $property): array } /** - * @return array{PhpDocNode, string}|null + * @return array{PhpDocNode, int, string}|null */ private function getDocBlockFromProperty(string $class, string $property): ?array { @@ -221,7 +221,13 @@ private function getDocBlockFromProperty(string $class, string $property): ?arra return null; } - if (null === $rawDocNode = $reflectionProperty->getDocComment() ?: null) { + $source = self::PROPERTY; + + if ($reflectionProperty->isPromoted()) { + $constructor = new \ReflectionMethod($class, '__construct'); + $rawDocNode = $constructor->getDocComment(); + $source = self::MUTATOR; + } elseif (null === $rawDocNode = $reflectionProperty->getDocComment() ?: null) { return null; } @@ -229,7 +235,7 @@ private function getDocBlockFromProperty(string $class, string $property): ?arra $phpDocNode = $this->phpDocParser->parse($tokens); $tokens->consumeTokenType(Lexer::TOKEN_END); - return [$phpDocNode, $reflectionProperty->class]; + return [$phpDocNode, $source, $reflectionProperty->class]; } /** diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php index 26077f7e528d..0cf346fce03c 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php @@ -17,6 +17,7 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultValue; 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\RootDummy\RootDummyItem; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsedInTrait; use Symfony\Component\PropertyInfo\Tests\Fixtures\TraitUsage\DummyUsingTrait; @@ -434,6 +435,21 @@ public function testDummyNamespaceWithProperty() $this->assertEquals('A\Property', $phpStanTypes[0]->getClassName()); $this->assertEquals($phpDocTypes[0]->getClassName(), $phpStanTypes[0]->getClassName()); } + + /** + * @dataProvider php80TypesProvider + */ + public function testExtractPhp80Type($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes(Php80Dummy::class, $property, [])); + } + + public function php80TypesProvider() + { + return [ + ['promotedAndMutated', [new Type(Type::BUILTIN_TYPE_STRING)]], + ]; + } } class PhpStanOmittedParamTagTypeDocBlock
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: