Skip to content

Commit

Permalink
feature #34557 [PropertyInfo] Add support for typed properties (PHP 7…
Browse files Browse the repository at this point in the history
….4) (dunglas)

This PR was squashed before being merged into the 5.1-dev branch (closes #34557).

Discussion
----------

[PropertyInfo] Add support for typed properties (PHP 7.4)

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | n/a <!-- prefix each issue number with "Fix #", if any -->
| License       | MIT
| Doc PR        | n/a

Add support for [typed properties](https://wiki.php.net/rfc/typed_properties_v2), a new feature introduced in PHP 7.4:

```php
class Foo
{
    public Bar $bar;
    private ?bool $nullableBoolProp;
}

$this->extractor->getTypes(Foo::class, 'bar'); // Type[]
$this->extractor->getTypes(Foo::class, 'nullableBoolProp'); // Type[]
```

#SymfonyHackday

Commits
-------

7edfe4f [PropertyInfo] Add support for typed properties (PHP 7.4)
  • Loading branch information
fabpot committed Nov 25, 2019
2 parents adbc1df + 7edfe4f commit 3888312
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ public function getProperties(string $class, array $context = []): ?array
*/
public function getTypes(string $class, string $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;
}
Expand Down Expand Up @@ -227,7 +239,7 @@ private function extractFromMutator(string $class, string $property): ?array
if (!$reflectionType = $reflectionParameter->getType()) {
return null;
}
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod);
$type = $this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass());

if (\in_array($prefix, $this->arrayMutatorPrefixes)) {
$type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type);
Expand All @@ -249,7 +261,7 @@ private function extractFromAccessor(string $class, string $property): ?array
}

if ($reflectionType = $reflectionMethod->getReturnType()) {
return [$this->extractFromReflectionType($reflectionType, $reflectionMethod)];
return [$this->extractFromReflectionType($reflectionType, $reflectionMethod->getDeclaringClass())];
}

if (\in_array($prefix, ['is', 'can', 'has'])) {
Expand Down Expand Up @@ -284,7 +296,7 @@ private function extractFromConstructor(string $class, string $property): ?array
}
$reflectionType = $parameter->getType();

return $reflectionType ? [$this->extractFromReflectionType($reflectionType, $constructor)] : null;
return $reflectionType ? [$this->extractFromReflectionType($reflectionType, $constructor->getDeclaringClass())] : null;
}

if ($parentClass = $reflectionClass->getParentClass()) {
Expand Down Expand Up @@ -313,7 +325,7 @@ private function extractFromDefaultValue(string $class, string $property): ?arra
return [new Type(static::MAP_TYPES[$type] ?? $type)];
}

private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod): Type
private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionClass $declaringClass): Type
{
$phpTypeOrClass = $reflectionType->getName();
$nullable = $reflectionType->allowsNull();
Expand All @@ -325,18 +337,18 @@ private function extractFromReflectionType(\ReflectionType $reflectionType, \Ref
} elseif ($reflectionType->isBuiltin()) {
$type = new Type($phpTypeOrClass, $nullable);
} else {
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod));
$type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $declaringClass));
}

return $type;
}

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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
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;

/**
Expand Down Expand Up @@ -365,4 +366,13 @@ public function constructorTypesProvider(): array
[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'));
}
}
21 changes: 21 additions & 0 deletions src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php74Dummy.php
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 3888312

Please sign in to comment.