diff --git a/src/Types/AbstractList.php b/src/Types/AbstractList.php index 83f032d..831be40 100644 --- a/src/Types/AbstractList.php +++ b/src/Types/AbstractList.php @@ -45,6 +45,11 @@ public function __construct(?Type $valueType = null, ?Type $keyType = null) $this->keyType = $keyType; } + /** + * Returns a rendered output of the Type as it would be used in a DocBlock. + */ + abstract public function __toString(): string; + public function getOriginalKeyType(): ?Type { return $this->keyType; @@ -70,24 +75,4 @@ public function getValueType(): Type { return $this->valueType ?? $this->defaultValueType; } - - /** - * Returns a rendered output of the Type as it would be used in a DocBlock. - */ - public function __toString(): string - { - if ($this->valueType === null) { - return 'array'; - } - - if ($this->keyType) { - return 'array<' . $this->keyType . ', ' . $this->valueType . '>'; - } - - if ($this->valueType instanceof Compound) { - return '(' . $this->valueType . ')[]'; - } - - return $this->valueType . '[]'; - } } diff --git a/src/Types/Array_.php b/src/Types/Array_.php index bc17225..b5e7eab 100644 --- a/src/Types/Array_.php +++ b/src/Types/Array_.php @@ -13,6 +13,9 @@ namespace phpDocumentor\Reflection\Types; +use function preg_match; +use function substr; + /** * Represents an array type as described in the PSR-5, the PHPDoc Standard. * @@ -26,4 +29,22 @@ */ class Array_ extends AbstractList { + public function __toString(): string + { + if ($this->valueType === null) { + return 'array'; + } + + $valueTypeString = (string) $this->valueType; + + if ($this->keyType) { + return 'array<' . $this->keyType . ', ' . $valueTypeString . '>'; + } + + if (!preg_match('/[^\w\\\\]/', $valueTypeString) || substr($valueTypeString, -2, 2) === '[]') { + return $valueTypeString . '[]'; + } + + return 'array<' . $valueTypeString . '>'; + } } diff --git a/tests/unit/TypeResolverTest.php b/tests/unit/TypeResolverTest.php index 04c92c0..0dd087d 100644 --- a/tests/unit/TypeResolverTest.php +++ b/tests/unit/TypeResolverTest.php @@ -379,7 +379,7 @@ public function testResolvingArrayExpressionObjectsTypes(): void $resolvedType = $fixture->resolve('(\stdClass|Reflection\DocBlock)[]', new Context('phpDocumentor')); $this->assertInstanceOf(Array_::class, $resolvedType); - $this->assertSame('(\stdClass|\phpDocumentor\Reflection\DocBlock)[]', (string) $resolvedType); + $this->assertSame('array<\stdClass|\phpDocumentor\Reflection\DocBlock>', (string) $resolvedType); $valueType = $resolvedType->getValueType(); @@ -408,7 +408,7 @@ public function testResolvingArrayExpressionSimpleTypes(): void $resolvedType = $fixture->resolve('(string|\stdClass|boolean)[]', new Context('')); $this->assertInstanceOf(Array_::class, $resolvedType); - $this->assertSame('(string|\stdClass|bool)[]', (string) $resolvedType); + $this->assertSame('array', (string) $resolvedType); $valueType = $resolvedType->getValueType(); @@ -440,7 +440,7 @@ public function testResolvingArrayOfArrayExpressionTypes(): void $resolvedType = $fixture->resolve('(string|\stdClass)[][]', new Context('')); $this->assertInstanceOf(Array_::class, $resolvedType); - $this->assertSame('(string|\stdClass)[][]', (string) $resolvedType); + $this->assertSame('array>', (string) $resolvedType); $parentArrayType = $resolvedType->getValueType(); $this->assertInstanceOf(Array_::class, $parentArrayType); @@ -486,7 +486,7 @@ public function testResolvingArrayExpressionOrCompoundTypes(): void $resolvedType = $fixture->resolve('\stdClass|(string|\stdClass)[]|bool', new Context('')); $this->assertInstanceOf(Compound::class, $resolvedType); - $this->assertSame('\stdClass|(string|\stdClass)[]|bool', (string) $resolvedType); + $this->assertSame('\stdClass|array|bool', (string) $resolvedType); $firstType = $resolvedType->get(0); $this->assertInstanceOf(Object_::class, $firstType); diff --git a/tests/unit/Types/ArrayTest.php b/tests/unit/Types/ArrayTest.php index 8201f29..2425319 100644 --- a/tests/unit/Types/ArrayTest.php +++ b/tests/unit/Types/ArrayTest.php @@ -14,6 +14,10 @@ namespace phpDocumentor\Reflection\Types; use phpDocumentor\Reflection\Fqsen; +use phpDocumentor\Reflection\PseudoTypes\ArrayShape; +use phpDocumentor\Reflection\PseudoTypes\ArrayShapeItem; +use phpDocumentor\Reflection\PseudoTypes\ObjectShape; +use phpDocumentor\Reflection\PseudoTypes\ObjectShapeItem; use PHPUnit\Framework\TestCase; final class ArrayTest extends TestCase @@ -63,8 +67,27 @@ public function provideToStringData(): array 'simple array' => [new Array_(), 'array'], 'array of mixed' => [new Array_(new Mixed_()), 'mixed[]'], 'array of single type' => [new Array_(new String_()), 'string[]'], - 'array of compound type' => [new Array_(new Compound([new Integer(), new String_()])), '(int|string)[]'], + 'multidimensional array' => [new Array_(new Array_(new String_())), 'string[][]'], + 'array of compound type' => [new Array_(new Compound([new Integer(), new String_()])), 'array'], 'array with key type' => [new Array_(new String_(), new Integer()), 'array'], + 'array of array shapes' => [ + new Array_( + new ArrayShape( + new ArrayShapeItem('foo', new String_(), false), + new ArrayShapeItem('bar', new Integer(), false) + ) + ), + 'array', + ], + 'array of object shapes' => [ + new Array_( + new ObjectShape( + new ObjectShapeItem('foo', new String_(), false), + new ObjectShapeItem('bar', new Integer(), false) + ) + ), + 'array', + ], ]; } } diff --git a/tests/unit/Types/ContextFactoryTest.php b/tests/unit/Types/ContextFactoryTest.php index 5d9a13e..a2eb0a7 100644 --- a/tests/unit/Types/ContextFactoryTest.php +++ b/tests/unit/Types/ContextFactoryTest.php @@ -262,5 +262,10 @@ public function assertNamespaceAliasesFrom(Context $context): void class Foo extends AbstractList { // dummy class + + public function __toString(): string + { + return ''; + } } }