From 38dd2a198f60d0093fe7936ac673035b5962d18d Mon Sep 17 00:00:00 2001 From: Matt Janssen Date: Fri, 11 Sep 2020 12:22:52 +0000 Subject: [PATCH] Adding support for PHP 7.4 typed properties --- .scrutinizer.yml | 2 +- .travis.yml | 9 --- composer.json | 2 +- src/Internal/TypeTokenFactory.php | 5 ++ tests/Mock/AddressMock.php | 5 +- tests/Mock/AnnotatedMock.php | 2 +- tests/Mock/ChildClass.php | 2 + tests/Mock/ChildClassParent.php | 2 +- tests/Mock/ClassWithoutParent.php | 2 +- tests/Mock/DocblockType/DocblockMock.php | 33 ++++++++++- tests/Mock/ExcludedClassMock.php | 2 +- tests/Mock/UserMock.php | 5 +- tests/Mock/UserMockVirtual.php | 5 +- .../Data/ReflectionPropertySetFactoryTest.php | 1 + tests/Unit/Internal/TypeTokenFactoryTest.php | 56 +++++++++++++++++++ 15 files changed, 105 insertions(+), 28 deletions(-) diff --git a/.scrutinizer.yml b/.scrutinizer.yml index b720a3d..b1caaae 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -7,7 +7,7 @@ build: tests-and-coverage: environment: php: - version: 7.1 + version: 7.4 tests: override: - phpcs-run diff --git a/.travis.yml b/.travis.yml index 42e091e..d4a8eb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,9 +2,6 @@ sudo: false language: php php: - - 7.1 - - 7.2 - - 7.3 - 7.4 env: @@ -13,12 +10,6 @@ env: - SF_CACHE=4.3 - SF_CACHE=5 -jobs: - exclude: - - php: 7.1 - env: - - SF_CACHE=5 - before_script: - composer install --no-interaction -o - if [ "$SF_CACHE" = "3" ]; then composer require symfony/cache:^3.3; fi; diff --git a/composer.json b/composer.json index 4e8eb55..73c13c9 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ } ], "require": { - "php": ">=7.1", + "php": ">=7.4", "phpdocumentor/reflection-docblock": "^3.2.3|^4.0.1", "tebru/php-type": "^0.1.7", "tebru/doctrine-annotation-reader": "^0.3.7", diff --git a/src/Internal/TypeTokenFactory.php b/src/Internal/TypeTokenFactory.php index 0ebf0e9..8f92dcd 100644 --- a/src/Internal/TypeTokenFactory.php +++ b/src/Internal/TypeTokenFactory.php @@ -100,6 +100,11 @@ public function create( } } + if ($property !== null && $property->getType() !== null) { + $propertyType = TypeToken::create($property->getType()->getName()); + return $this->checkGenericArray($propertyType, $property, $getterMethod, $setterMethod); + } + $type = $this->checkDocBlocks($property, $getterMethod, $setterMethod); if ($type !== null) { return $this->checkGenericArray( diff --git a/tests/Mock/AddressMock.php b/tests/Mock/AddressMock.php index 25ef82b..cf80282 100644 --- a/tests/Mock/AddressMock.php +++ b/tests/Mock/AddressMock.php @@ -18,10 +18,7 @@ class AddressMock */ private $street; - /** - * @var string - */ - private $city; + private string $city; /** * @var string diff --git a/tests/Mock/AnnotatedMock.php b/tests/Mock/AnnotatedMock.php index 0219ebe..cbdfc51 100644 --- a/tests/Mock/AnnotatedMock.php +++ b/tests/Mock/AnnotatedMock.php @@ -21,7 +21,7 @@ class AnnotatedMock */ private $fooBar; - private $fooBarBaz; + private float $fooBarBaz; /** * @Gson\VirtualProperty("vfoo") diff --git a/tests/Mock/ChildClass.php b/tests/Mock/ChildClass.php index c618c7f..e29c4de 100644 --- a/tests/Mock/ChildClass.php +++ b/tests/Mock/ChildClass.php @@ -41,6 +41,8 @@ class ChildClass extends ChildClassParent */ private $default = 1; + private array $typedArray; + public function getBaz() { return $this->baz; diff --git a/tests/Mock/ChildClassParent.php b/tests/Mock/ChildClassParent.php index 560f3f6..afdd6c1 100644 --- a/tests/Mock/ChildClassParent.php +++ b/tests/Mock/ChildClassParent.php @@ -26,6 +26,6 @@ class ChildClassParent extends ChildClassParent2 * @QuxAnnotation("qux") */ private $foo; - private $bar; + private string $bar; protected $baz; } diff --git a/tests/Mock/ClassWithoutParent.php b/tests/Mock/ClassWithoutParent.php index fc73127..94c4020 100644 --- a/tests/Mock/ClassWithoutParent.php +++ b/tests/Mock/ClassWithoutParent.php @@ -24,7 +24,7 @@ class ClassWithoutParent * @FooAnnotation("foo") * @BarAnnotation("bar") */ - private $foo; + private int $foo; /** * @FooAnnotation("foo2") diff --git a/tests/Mock/DocblockType/DocblockMock.php b/tests/Mock/DocblockType/DocblockMock.php index 353252e..27aa0a8 100644 --- a/tests/Mock/DocblockType/DocblockMock.php +++ b/tests/Mock/DocblockType/DocblockMock.php @@ -113,13 +113,18 @@ class DocblockMock /** * @var ArrayObject */ - private $classGlobal; + private ArrayObject $classGlobal; /** * @var array */ private $array; + /** + * @var int[] + */ + private array $fullyTypedArray; + /** * @var int[] */ @@ -160,6 +165,16 @@ class DocblockMock */ private $differentSetter; + /** + * @var ArrayObject + */ + private ArrayObject $differentGetterTyped; + + /** + * @var ArrayObject + */ + private ArrayObject $differentSetterTyped; + /** * @return int */ @@ -197,4 +212,20 @@ public function setDifferentSetter(array $foos): void { $this->differentSetter = $foos; } + + /** + * @return DocblockFoo[] + */ + public function getDifferentGetterTyped(): array + { + return $this->differentGetterTyped->getArrayCopy(); + } + + /** + * @param DocblockFoo[] $foos + */ + public function setDifferentSetterTyped(array $foos): void + { + $this->differentSetterTyped = new ArrayObject($foos); + } } diff --git a/tests/Mock/ExcludedClassMock.php b/tests/Mock/ExcludedClassMock.php index 6593f2e..fa3182f 100644 --- a/tests/Mock/ExcludedClassMock.php +++ b/tests/Mock/ExcludedClassMock.php @@ -21,5 +21,5 @@ class ExcludedClassMock * @Type("Tebru\Gson\Test\Mock\GsonMock") */ private $foo; - private $bar; + private bool $bar; } diff --git a/tests/Mock/UserMock.php b/tests/Mock/UserMock.php index 29a0e63..962a323 100644 --- a/tests/Mock/UserMock.php +++ b/tests/Mock/UserMock.php @@ -33,10 +33,7 @@ class UserMock */ private $password; - /** - * @var string - */ - private $name; + private string $name; /** * @var AddressMock diff --git a/tests/Mock/UserMockVirtual.php b/tests/Mock/UserMockVirtual.php index f43e532..e3a9f09 100644 --- a/tests/Mock/UserMockVirtual.php +++ b/tests/Mock/UserMockVirtual.php @@ -35,10 +35,7 @@ class UserMockVirtual */ private $password; - /** - * @var string - */ - private $name; + private string $name; /** * @var AddressMock diff --git a/tests/Unit/Internal/Data/ReflectionPropertySetFactoryTest.php b/tests/Unit/Internal/Data/ReflectionPropertySetFactoryTest.php index b119372..ecc3cce 100644 --- a/tests/Unit/Internal/Data/ReflectionPropertySetFactoryTest.php +++ b/tests/Unit/Internal/Data/ReflectionPropertySetFactoryTest.php @@ -48,6 +48,7 @@ public function testCreateWithParents(): void new ReflectionProperty(ChildClass::class, 'overridden'), new ReflectionProperty(ChildClass::class, 'withTypehint'), new ReflectionProperty(ChildClass::class, 'default'), + new ReflectionProperty(ChildClass::class, 'typedArray'), new ReflectionProperty(ChildClassParent::class, 'baz'), new ReflectionProperty(ChildClassParent2::class, 'qux'), new ReflectionProperty(ChildClassParent::class, 'bar'), diff --git a/tests/Unit/Internal/TypeTokenFactoryTest.php b/tests/Unit/Internal/TypeTokenFactoryTest.php index e8615da..71b1698 100644 --- a/tests/Unit/Internal/TypeTokenFactoryTest.php +++ b/tests/Unit/Internal/TypeTokenFactoryTest.php @@ -46,6 +46,40 @@ public function testCreateFromAnnotation(): void self::assertSame(ChildClass::class, $phpType->getRawType()); } + public function testCreateFromAnnotationWithTypedProperty(): void + { + $type = new Type(['value' => ChildClass::class]); + $annotations = new AnnotationCollection(); + $annotations->add($type); + + $factory = new TypeTokenFactory(); + $property = new ReflectionProperty(ChildClass::class, 'typedArray'); + $phpType = $factory->create($annotations, null, null, $property); + + self::assertSame(ChildClass::class, $phpType->getRawType()); + } + + public function testCreateFromPropertyType(): void + { + $annotations = new AnnotationCollection(); + $factory = new TypeTokenFactory(); + $property = new ReflectionProperty(ChildClass::class, 'typedArray'); + $phpType = $factory->create($annotations, null, null, $property); + + self::assertSame('array', $phpType->getRawType()); + } + + public function testCreateFromArrayPropertyTypeWithGeneric(): void + { + $annotations = new AnnotationCollection(); + $factory = new TypeTokenFactory(); + $property = new ReflectionProperty(DocblockMock::class, 'fullyTypedArray'); + $phpType = $factory->create($annotations, null, null, $property); + + self::assertSame(TypeToken::HASH, $phpType->getRawType()); + self::assertSame(TypeToken::INTEGER, $phpType->getGenerics()[0]->getRawType()); + } + public function testCreateFromSetterTypehint(): void { $annotations = new AnnotationCollection(); @@ -360,6 +394,28 @@ public function testCreateFromDocblockDifferentSetter(): void self::assertSame('array', (string)$phpType); } + public function testCreateFromDocblockDifferentGetterWithTypedProperty(): void + { + $annotations = new AnnotationCollection(); + $factory = new TypeTokenFactory(); + $property = new ReflectionProperty(DocblockMock::class, 'differentGetterTyped'); + $getter = new ReflectionMethod(DocblockMock::class, 'getDifferentGetterTyped'); + $phpType = $factory->create($annotations, $getter, null, $property); + + self::assertSame('array', (string)$phpType); + } + + public function testCreateFromDocblockDifferentSetterWithTypedProperty(): void + { + $annotations = new AnnotationCollection(); + $factory = new TypeTokenFactory(); + $property = new ReflectionProperty(DocblockMock::class, 'differentSetterTyped'); + $setter = new ReflectionMethod(DocblockMock::class, 'setDifferentSetterTyped'); + $phpType = $factory->create($annotations, null, $setter, $property); + + self::assertSame('array', (string)$phpType); + } + public function testCreateFromGetter(): void { $annotations = new AnnotationCollection();