From 48a106ab7a474499fc048d77dd4236a9f431ddf0 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 22 Mar 2021 15:19:00 +0100 Subject: [PATCH 1/2] Add failing test for nullable phpdoc When the property is typed with `@var string|null` everything works fine. But when it's typed in opposite order it breaks `@var null|string`: Undefined offset: 0 --- tests/Fixtures/ObjectWithPhpDocProperty.php | 10 ++++++++++ .../Driver/DocBlockTypeResolverTest.php | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/tests/Fixtures/ObjectWithPhpDocProperty.php b/tests/Fixtures/ObjectWithPhpDocProperty.php index 2b9daeaa6..1896445e8 100644 --- a/tests/Fixtures/ObjectWithPhpDocProperty.php +++ b/tests/Fixtures/ObjectWithPhpDocProperty.php @@ -11,4 +11,14 @@ final class ObjectWithPhpDocProperty */ private $emptyBlock; + /** + * @var string|null + */ + private $firstname; + + /** + * @var null|string + */ + private $lastname; + } diff --git a/tests/Metadata/Driver/DocBlockTypeResolverTest.php b/tests/Metadata/Driver/DocBlockTypeResolverTest.php index ead18be31..755c3cc50 100644 --- a/tests/Metadata/Driver/DocBlockTypeResolverTest.php +++ b/tests/Metadata/Driver/DocBlockTypeResolverTest.php @@ -22,4 +22,21 @@ public function testGetPropertyDocblockTypeHintDoesNotCrash(): void ) ); } + + public function testGetPropertyDocblockTypeHintDoesNotCrashWhenUnionType(): void + { + $resolver = new DocBlockTypeResolver(); + self::assertSame( + 'string', + $resolver->getPropertyDocblockTypeHint( + new ReflectionProperty(ObjectWithPhpDocProperty::class, 'firstname') + ) + ); + self::assertSame( + 'string', + $resolver->getPropertyDocblockTypeHint( + new ReflectionProperty(ObjectWithPhpDocProperty::class, 'lastname') + ) + ); + } } From 413909d56af5574de77ab0c13bfed77fd686c02b Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Mon, 22 Mar 2021 15:24:05 +0100 Subject: [PATCH 2/2] Use array_values When `filterNullFromTypes` receives the following `[ 0 => IdentifierTypeNode("null"), 1 => IdentifierTypeNode("string") ]` types, it will map the one that is called `"null"` with `null` like this: `[ 0 => null, 1 => IdentifierTypeNode("string") ]`. It then passes the array to `array_filter` that removes all the `null` values, leaving the following array as a result: `[1 => IdentifierTypeNode("string") ]`. The problem is that `array_filter` keeps the keys intact, while the code that uses this doesn't expect it. By using `array_values` we get a clean array again: `[0 => IdentifierTypeNode("string") ]`. --- src/Metadata/Driver/DocBlockTypeResolver.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Metadata/Driver/DocBlockTypeResolver.php b/src/Metadata/Driver/DocBlockTypeResolver.php index 77e5b844c..dd5201a1d 100644 --- a/src/Metadata/Driver/DocBlockTypeResolver.php +++ b/src/Metadata/Driver/DocBlockTypeResolver.php @@ -143,9 +143,9 @@ private function flattenVarTagValueTypes(array $varTagValues): array */ private function filterNullFromTypes(array $types): array { - return array_filter(array_map(function (TypeNode $node) { + return array_values(array_filter(array_map(function (TypeNode $node) { return $this->isNullType($node) ? null : $node; - }, $types)); + }, $types))); } /**