bug #37971 [PropertyInfo] Backport support for typed properties (PHP 7.4) (dunglas)
This PR was merged into the 4.4 branch.
Discussion
----------
[PropertyInfo] Backport support for typed properties (PHP 7.4)
| Q | A
| ------------- | ---
| Branch? | 4.4 <!-- see below -->
| Bug fix? | yes
| New feature? | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets | N/A. <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/13719 to be fixed
Backports #34557 as suggested.
One of my workmate hit this issue with the Serializer component and it was not obvious for him why it was not working, without hint.
Commits
-------
1b19f255a3
[PropertyInfo] Backport support for typed properties (PHP 7.4)
This commit is contained in:
commit
03d494ddde
@ -139,6 +139,18 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
*/
|
||||
public function getTypes($class, $property, array $context = []): ?array
|
||||
{
|
||||
if (\PHP_VERSION_ID >= 70400) {
|
||||
try {
|
||||
$reflectionProperty = new \ReflectionProperty($class, $property);
|
||||
$type = $reflectionProperty->getType();
|
||||
if (null !== $type) {
|
||||
return $this->extractFromReflectionType($type, $reflectionProperty->getDeclaringClass());
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
if ($fromMutator = $this->extractFromMutator($class, $property)) {
|
||||
return $fromMutator;
|
||||
}
|
||||
@ -233,7 +245,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
if (!$reflectionType = $reflectionParameter->getType()) {
|
||||
return null;
|
||||
}
|
||||
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod);
|
||||
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass());
|
||||
|
||||
if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) {
|
||||
$type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])];
|
||||
@ -255,7 +267,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
}
|
||||
|
||||
if ($reflectionType = $reflectionMethod->getReturnType()) {
|
||||
return $this->extractFromReflectionType($reflectionType, $reflectionMethod);
|
||||
return $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass());
|
||||
}
|
||||
|
||||
if (\in_array($prefix, ['is', 'can', 'has'])) {
|
||||
@ -290,7 +302,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
}
|
||||
$reflectionType = $parameter->getType();
|
||||
|
||||
return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor) : null;
|
||||
return $reflectionType ? $this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass()) : null;
|
||||
}
|
||||
|
||||
if ($parentClass = $reflectionClass->getParentClass()) {
|
||||
@ -319,7 +331,7 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
return [new Type(static::MAP_TYPES[$type] ?? $type)];
|
||||
}
|
||||
|
||||
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod): array
|
||||
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): array
|
||||
{
|
||||
$types = [];
|
||||
$nullable = $reflectionType->allowsNull();
|
||||
@ -337,19 +349,19 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
|
||||
} elseif ($type->isBuiltin()) {
|
||||
$types[] = new Type($phpTypeOrClass, $nullable);
|
||||
} else {
|
||||
$types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod));
|
||||
$types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass));
|
||||
}
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
private function resolveTypeName(string $name, \ReflectionMethod $reflectionMethod): string
|
||||
private function resolveTypeName(string $name, \ReflectionClass $declaringClass): string
|
||||
{
|
||||
if ('self' === $lcName = strtolower($name)) {
|
||||
return $reflectionMethod->getDeclaringClass()->name;
|
||||
return $declaringClass->name;
|
||||
}
|
||||
if ('parent' === $lcName && $parent = $reflectionMethod->getDeclaringClass()->getParentClass()) {
|
||||
if ('parent' === $lcName && $parent = $declaringClass->getParentClass()) {
|
||||
return $parent->name;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy;
|
||||
use Symfony\Component\PropertyInfo\Tests\Fixtures\NotInstantiable;
|
||||
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy;
|
||||
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2;
|
||||
use Symfony\Component\PropertyInfo\Tests\Fixtures\Php74Dummy;
|
||||
use Symfony\Component\PropertyInfo\Type;
|
||||
|
||||
/**
|
||||
@ -389,4 +390,13 @@ class ReflectionExtractorTest extends TestCase
|
||||
[DefaultValue::class, 'foo', null],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 7.4
|
||||
*/
|
||||
public function testTypedProperties(): void
|
||||
{
|
||||
$this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)], $this->extractor->getTypes(Php74Dummy::class, 'dummy'));
|
||||
$this->assertEquals([new Type(Type::BUILTIN_TYPE_BOOL, true)], $this->extractor->getTypes(Php74Dummy::class, 'nullableBoolProp'));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
|
||||
|
||||
/**
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class Php74Dummy
|
||||
{
|
||||
public Dummy $dummy;
|
||||
private ?bool $nullableBoolProp;
|
||||
}
|
Reference in New Issue
Block a user