From ac08e7c3204ce6d1dd035d7302869912d1ced0dc Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Mon, 2 Sep 2019 11:55:24 +0200 Subject: [PATCH] cleanup type resolving --- ...outerListToControllerAnnotationsRector.php | 36 +-- .../AddArrayReturnDocTypeRector.php | 15 +- .../ReturnTypeDeclarationRector.php | 7 +- .../src/TypeDeclarationToStringConverter.php | 46 ++++ ...tterTypeDeclarationPropertyTypeInferer.php | 44 +--- .../src/TypeInferer/ReturnTypeInferer.php | 26 ++- ...ReturnTypeDeclarationReturnTypeInferer.php | 43 ++++ .../AddArrayReturnDocTypeRectorTest.php | 2 +- .../Manipulator/ClassMethodManipulator.php | 34 --- .../Manipulator/FunctionLikeManipulator.php | 211 ------------------ 10 files changed, 161 insertions(+), 303 deletions(-) create mode 100644 packages/TypeDeclaration/src/TypeDeclarationToStringConverter.php create mode 100644 packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php diff --git a/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php b/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php index 06256c3e5025..cbd879506b87 100644 --- a/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php +++ b/packages/NetteToSymfony/src/Rector/ClassMethod/RouterListToControllerAnnotationsRector.php @@ -14,10 +14,10 @@ use Rector\NetteToSymfony\Route\RouteInfoFactory; use Rector\NodeContainer\ParsedNodesByType; use Rector\NodeTypeResolver\PhpDoc\NodeAnalyzer\DocBlockManipulator; -use Rector\PhpParser\Node\Manipulator\ClassMethodManipulator; use Rector\Rector\AbstractRector; use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; +use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; use Rector\Util\RectorStrings; use ReflectionMethod; @@ -58,15 +58,15 @@ final class RouterListToControllerAnnotationsRector extends AbstractRector private $routeInfoFactory; /** - * @var ClassMethodManipulator + * @var ReturnTypeInferer */ - private $classMethodManipulator; + private $returnTypeInferer; public function __construct( ParsedNodesByType $parsedNodesByType, - ClassMethodManipulator $classMethodManipulator, DocBlockManipulator $docBlockManipulator, RouteInfoFactory $routeInfoFactory, + ReturnTypeInferer $returnTypeInferer, string $routeListClass = 'Nette\Application\Routers\RouteList', string $routerClass = 'Nette\Application\IRouter', string $routeAnnotationClass = 'Symfony\Component\Routing\Annotation\Route' @@ -77,7 +77,7 @@ public function __construct( $this->docBlockManipulator = $docBlockManipulator; $this->routeAnnotationClass = $routeAnnotationClass; $this->routeInfoFactory = $routeInfoFactory; - $this->classMethodManipulator = $classMethodManipulator; + $this->returnTypeInferer = $returnTypeInferer; } public function getDefinition(): RectorDefinition @@ -153,12 +153,8 @@ public function refactor(Node $node): ?Node return null; } - $nodeReturnTypes = $this->classMethodManipulator->resolveReturnType($node); - if ($nodeReturnTypes === []) { - return null; - } - - if (! in_array($this->routeListClass, $nodeReturnTypes, true)) { + $inferedReturnTypes = $this->returnTypeInferer->inferFunctionLike($node); + if (! in_array($this->routeListClass, $inferedReturnTypes, true)) { return null; } @@ -176,13 +172,7 @@ public function refactor(Node $node): ?Node continue; } - $phpDocTagNode = new SymfonyRoutePhpDocTagNode( - $this->routeAnnotationClass, - $routeInfo->getPath(), - null, - $routeInfo->getHttpMethods() - ); - + $phpDocTagNode = $this->createSymfonyRoutePhpDocTagNode($routeInfo); $this->docBlockManipulator->addTag($classMethod, $phpDocTagNode); } @@ -338,4 +328,14 @@ private function resolvePathFromClassAndMethodNodes(Class_ $classNode, ClassMeth return $presenterPart . '/' . $actionPart; } + + private function createSymfonyRoutePhpDocTagNode(RouteInfo $routeInfo): SymfonyRoutePhpDocTagNode + { + return new SymfonyRoutePhpDocTagNode( + $this->routeAnnotationClass, + $routeInfo->getPath(), + null, + $routeInfo->getHttpMethods() + ); + } } diff --git a/packages/TypeDeclaration/src/Rector/ClassMethod/AddArrayReturnDocTypeRector.php b/packages/TypeDeclaration/src/Rector/ClassMethod/AddArrayReturnDocTypeRector.php index 7bb3eff72411..891c953d9573 100644 --- a/packages/TypeDeclaration/src/Rector/ClassMethod/AddArrayReturnDocTypeRector.php +++ b/packages/TypeDeclaration/src/Rector/ClassMethod/AddArrayReturnDocTypeRector.php @@ -9,6 +9,7 @@ use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; +use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTypeDeclarationReturnTypeInferer; /** * @sponsor Thanks https://spaceflow.io/ for sponsoring this rule - visit them on https://github.com/SpaceFlow-app @@ -89,16 +90,22 @@ public function refactor(Node $node): ?Node return null; } - $inferedTypes = $this->returnTypeInferer->inferFunctionLike($node); + $inferedTypes = $this->returnTypeInferer->inferFunctionLikeWithExcludedInferers( + $node, + [ReturnTypeDeclarationReturnTypeInferer::class] + ); if ($inferedTypes === ['void']) { return null; } - if ($inferedTypes !== []) { - $docType = implode('|', $inferedTypes); - $this->docBlockManipulator->addReturnTag($node, $docType); + if ($inferedTypes === []) { + return null; } + $docType = implode('|', $inferedTypes); + + $this->docBlockManipulator->addReturnTag($node, $docType); + return $node; } diff --git a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php index a7acc272c652..5654136c1350 100644 --- a/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php +++ b/packages/TypeDeclaration/src/Rector/FunctionLike/ReturnTypeDeclarationRector.php @@ -14,6 +14,7 @@ use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer; +use Rector\TypeDeclaration\TypeInferer\ReturnTypeInferer\ReturnTypeDeclarationReturnTypeInferer; final class ReturnTypeDeclarationRector extends AbstractTypeDeclarationRector { @@ -94,7 +95,11 @@ public function refactor(Node $node): ?Node $hasNewType = $node->returnType->getAttribute(self::HAS_NEW_INHERITED_TYPE, false); } - $inferedTypes = $this->returnTypeInferer->inferFunctionLike($node); + $inferedTypes = $this->returnTypeInferer->inferFunctionLikeWithExcludedInferers( + $node, + [ReturnTypeDeclarationReturnTypeInferer::class] + ); + if ($inferedTypes === []) { return null; } diff --git a/packages/TypeDeclaration/src/TypeDeclarationToStringConverter.php b/packages/TypeDeclaration/src/TypeDeclarationToStringConverter.php new file mode 100644 index 000000000000..6eff555ebcc9 --- /dev/null +++ b/packages/TypeDeclaration/src/TypeDeclarationToStringConverter.php @@ -0,0 +1,46 @@ +nameResolver = $nameResolver; + } + + /** + * @return string[] + */ + public function resolveFunctionLikeReturnTypeToString(FunctionLike $functionLike): array + { + if ($functionLike->getReturnType() === null) { + return []; + } + + $returnType = $functionLike->getReturnType(); + + $types = []; + + $type = $returnType instanceof NullableType ? $returnType->type : $returnType; + $result = $this->nameResolver->getName($type); + if ($result !== null) { + $types[] = $result; + } + + if ($returnType instanceof NullableType) { + $types[] = 'null'; + } + + return $types; + } +} diff --git a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php index 610cda68dec2..0cc03de4c699 100644 --- a/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/PropertyTypeInferer/GetterTypeDeclarationPropertyTypeInferer.php @@ -2,21 +2,28 @@ namespace Rector\TypeDeclaration\TypeInferer\PropertyTypeInferer; -use PhpParser\Node\Expr\Closure; use PhpParser\Node\Expr\PropertyFetch; -use PhpParser\Node\FunctionLike; -use PhpParser\Node\NullableType; use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\ClassMethod; -use PhpParser\Node\Stmt\Function_; use PhpParser\Node\Stmt\Property; use PhpParser\Node\Stmt\Return_; use Rector\NodeTypeResolver\Node\AttributeKey; use Rector\TypeDeclaration\Contract\TypeInferer\PropertyTypeInfererInterface; +use Rector\TypeDeclaration\TypeDeclarationToStringConverter; use Rector\TypeDeclaration\TypeInferer\AbstractTypeInferer; final class GetterTypeDeclarationPropertyTypeInferer extends AbstractTypeInferer implements PropertyTypeInfererInterface { + /** + * @var TypeDeclarationToStringConverter + */ + private $typeDeclarationToStringConverter; + + public function __construct(TypeDeclarationToStringConverter $typeDeclarationToStringConverter) + { + $this->typeDeclarationToStringConverter = $typeDeclarationToStringConverter; + } + /** * @return string[] */ @@ -33,7 +40,7 @@ public function inferProperty(Property $property): array continue; } - $returnTypes = $this->resolveReturnTypeToString($classMethod); + $returnTypes = $this->typeDeclarationToStringConverter->resolveFunctionLikeReturnTypeToString($classMethod); // let PhpDoc solve that later for more precise type if ($returnTypes === ['array']) { return []; @@ -74,31 +81,4 @@ private function hasClassMethodOnlyStatementReturnOfPropertyFetch( return $this->nameResolver->isName($return->expr, $propertyName); } - - /** - * @param Function_|ClassMethod|Closure $functionLike - * @return string[] - */ - private function resolveReturnTypeToString(FunctionLike $functionLike): array - { - if ($functionLike->getReturnType() === null) { - return []; - } - - $returnType = $functionLike->getReturnType(); - - $types = []; - - $type = $returnType instanceof NullableType ? $returnType->type : $returnType; - $result = $this->nameResolver->getName($type); - if ($result !== null) { - $types[] = $result; - } - - if ($returnType instanceof NullableType) { - $types[] = 'null'; - } - - return $types; - } } diff --git a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer.php index a16f8af0193d..76dd045d082c 100644 --- a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer.php +++ b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer.php @@ -25,8 +25,30 @@ public function __construct(array $returnTypeInferers) */ public function inferFunctionLike(FunctionLike $functionLike): array { - foreach ($this->returnTypeInferers as $returnTypeInferers) { - $types = $returnTypeInferers->inferFunctionLike($functionLike); + foreach ($this->returnTypeInferers as $returnTypeInferer) { + $types = $returnTypeInferer->inferFunctionLike($functionLike); + if ($types !== []) { + return $types; + } + } + + return []; + } + + /** + * @param string[] $excludedInferers + * @return string[] + */ + public function inferFunctionLikeWithExcludedInferers(FunctionLike $functionLike, array $excludedInferers): array + { + foreach ($this->returnTypeInferers as $returnTypeInferer) { + foreach ($excludedInferers as $excludedInferer) { + if (is_a($returnTypeInferer, $excludedInferer, true)) { + continue 2; + } + } + + $types = $returnTypeInferer->inferFunctionLike($functionLike); if ($types !== []) { return $types; } diff --git a/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php new file mode 100644 index 000000000000..755498d97f2d --- /dev/null +++ b/packages/TypeDeclaration/src/TypeInferer/ReturnTypeInferer/ReturnTypeDeclarationReturnTypeInferer.php @@ -0,0 +1,43 @@ +typeDeclarationToStringConverter = $typeDeclarationToStringConverter; + } + + /** + * @return string[] + */ + public function inferFunctionLike(FunctionLike $functionLike): array + { + if ($functionLike->getReturnType() === null) { + return []; + } + + // resolve later with more precise type, e.g. Type[] + if ($this->nameResolver->isNames($functionLike->getReturnType(), ['array', 'iterable'])) { + return []; + } + + return $this->typeDeclarationToStringConverter->resolveFunctionLikeReturnTypeToString($functionLike); + } + + public function getPriority(): int + { + return 2000; + } +} diff --git a/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php b/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php index e81991e53584..dfb18da631c9 100644 --- a/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php +++ b/packages/TypeDeclaration/tests/Rector/ClassMethod/AddArrayReturnDocTypeRector/AddArrayReturnDocTypeRectorTest.php @@ -17,7 +17,7 @@ public function test(): void __DIR__ . '/Fixture/simple_array.php.inc', __DIR__ . '/Fixture/add_without_return_type_declaration.php.inc', __DIR__ . '/Fixture/fix_incorrect_array.php.inc', - // skip + // skip __DIR__ . '/Fixture/skip_constructor.php.inc', __DIR__ . '/Fixture/skip_array_after_array_type.php.inc', __DIR__ . '/Fixture/skip_shorten_class_name.php.inc', diff --git a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php index 145ff85fd8bc..4281494795ec 100644 --- a/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php +++ b/src/PhpParser/Node/Manipulator/ClassMethodManipulator.php @@ -33,11 +33,6 @@ final class ClassMethodManipulator */ private $nodeTypeResolver; - /** - * @var FunctionLikeManipulator - */ - private $functionLikeManipulator; - /** * @var NameResolver */ @@ -52,14 +47,12 @@ public function __construct( BetterNodeFinder $betterNodeFinder, BetterStandardPrinter $betterStandardPrinter, NodeTypeResolver $nodeTypeResolver, - FunctionLikeManipulator $functionLikeManipulator, NameResolver $nameResolver, ValueResolver $valueResolver ) { $this->betterNodeFinder = $betterNodeFinder; $this->betterStandardPrinter = $betterStandardPrinter; $this->nodeTypeResolver = $nodeTypeResolver; - $this->functionLikeManipulator = $functionLikeManipulator; $this->nameResolver = $nameResolver; $this->valueResolver = $valueResolver; } @@ -121,33 +114,6 @@ public function hasParentMethodOrInterfaceMethod(ClassMethod $classMethod, ?stri return false; } - /** - * @return string[] - */ - public function resolveReturnType(ClassMethod $classMethod): array - { - if ($classMethod->returnType !== null) { - return $this->nodeTypeResolver->resolve($classMethod->returnType); - } - - $staticReturnType = $this->functionLikeManipulator->resolveStaticReturnTypeInfo($classMethod); - if ($staticReturnType === null) { - return []; - } - - $getFqnTypeNode = $staticReturnType->getFqnTypeNode(); - if ($getFqnTypeNode === null) { - return []; - } - - $fqnTypeName = $this->nameResolver->getName($getFqnTypeNode); - if ($fqnTypeName === null) { - return []; - } - - return [$fqnTypeName]; - } - /** * Is method actually static, or has some $this-> calls? */ diff --git a/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php b/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php index d1e2f71eaedd..8e816486c3b8 100644 --- a/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php +++ b/src/PhpParser/Node/Manipulator/FunctionLikeManipulator.php @@ -2,62 +2,20 @@ namespace Rector\PhpParser\Node\Manipulator; -use Iterator; use PhpParser\Node; -use PhpParser\Node\Expr\ArrowFunction; -use PhpParser\Node\Expr\Closure; -use PhpParser\Node\Expr\Yield_; use PhpParser\Node\FunctionLike; -use PhpParser\Node\Identifier; -use PhpParser\Node\Name; -use PhpParser\Node\NullableType; -use PhpParser\Node\Stmt\ClassMethod; use PhpParser\Node\Stmt\Function_; -use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Return_; -use PhpParser\NodeTraverser; -use Rector\NodeTypeResolver\Node\AttributeKey; -use Rector\NodeTypeResolver\NodeTypeResolver; -use Rector\NodeTypeResolver\Php\ReturnTypeInfo; -use Rector\Php\PhpVersionProvider; -use Rector\Php\TypeAnalyzer; -use Rector\PhpParser\Node\BetterNodeFinder; use Rector\PhpParser\Node\Resolver\NameResolver; use Rector\PhpParser\NodeTraverser\CallableNodeTraverser; -use Rector\TypeDeclaration\Rector\FunctionLike\AbstractTypeDeclarationRector; final class FunctionLikeManipulator { - /** - * @var BetterNodeFinder - */ - private $betterNodeFinder; - - /** - * @var TypeAnalyzer - */ - private $typeAnalyzer; - - /** - * @var NodeTypeResolver - */ - private $nodeTypeResolver; - /** * @var NameResolver */ private $nameResolver; - /** - * @var bool - */ - private $isVoid = false; - - /** - * @var PhpVersionProvider - */ - private $phpVersionProvider; - /** * @var CallableNodeTraverser */ @@ -69,70 +27,15 @@ final class FunctionLikeManipulator private $propertyFetchManipulator; public function __construct( - BetterNodeFinder $betterNodeFinder, - TypeAnalyzer $typeAnalyzer, - NodeTypeResolver $nodeTypeResolver, NameResolver $nameResolver, - PhpVersionProvider $phpVersionProvider, CallableNodeTraverser $callableNodeTraverser, PropertyFetchManipulator $propertyFetchManipulator ) { - $this->betterNodeFinder = $betterNodeFinder; - $this->typeAnalyzer = $typeAnalyzer; - $this->nodeTypeResolver = $nodeTypeResolver; $this->nameResolver = $nameResolver; - $this->phpVersionProvider = $phpVersionProvider; $this->callableNodeTraverser = $callableNodeTraverser; $this->propertyFetchManipulator = $propertyFetchManipulator; } - /** - * Based on static analysis of code, looking for return types - * @param ClassMethod|Function_|Closure $functionLike - */ - public function resolveStaticReturnTypeInfo(FunctionLike $functionLike): ?ReturnTypeInfo - { - if ($this->shouldSkip($functionLike)) { - return null; - } - - // @todo decouple to return type inferer B-) - - // A. resolve from function return type - // skip "array" to get more precise types - if ($functionLike->returnType !== null && ! $this->nameResolver->isNames( - $functionLike->returnType, - ['array', 'iterable'] - )) { - $types = $this->resolveReturnTypeToString($functionLike->returnType); - - // do not override freshly added type declaration - if (! $functionLike->returnType->getAttribute( - AbstractTypeDeclarationRector::HAS_NEW_INHERITED_TYPE - ) && $types !== []) { - return new ReturnTypeInfo($types, $this->typeAnalyzer, $types); - } - } - - $this->isVoid = true; - - // B. resolve from return $x nodes - $types = $this->resolveTypesFromReturnNodes($functionLike); - - // C. resolve from yields - if ($types === []) { - $types = $this->resolveFromYieldNodes($functionLike); - } - - if ($this->isVoid) { - return new ReturnTypeInfo(['void'], $this->typeAnalyzer, ['void']); - } - - $types = array_filter($types); - - return new ReturnTypeInfo($types, $this->typeAnalyzer, $types); - } - /** * @return string[] */ @@ -165,118 +68,4 @@ public function getReturnedLocalPropertyNames(FunctionLike $functionLike): array return $returnedLocalPropertyNames; } - - private function shouldSkip(FunctionLike $functionLike): bool - { - if (! $functionLike instanceof ClassMethod) { - return false; - } - - $classNode = $functionLike->getAttribute(AttributeKey::CLASS_NODE); - // only class or trait method body can be analyzed for returns - if ($classNode instanceof Interface_) { - return true; - } - - // only methods that are not abstract can be analyzed for returns - return $functionLike->isAbstract(); - } - - /** - * @param Identifier|Name|NullableType $node - * @return string[] - */ - private function resolveReturnTypeToString(Node $node): array - { - $types = []; - - $type = $node instanceof NullableType ? $node->type : $node; - $result = $this->nameResolver->getName($type); - if ($result !== null) { - $types[] = $result; - } - - if ($node instanceof NullableType) { - $types[] = 'null'; - } - - return $types; - } - - /** - * @covered - * @param ClassMethod|Function_|Closure $functionLike - * @return string[] - */ - private function resolveTypesFromReturnNodes(FunctionLike $functionLike): array - { - // local - /** @var Return_[] $localReturnNodes */ - $localReturnNodes = []; - - $this->callableNodeTraverser->traverseNodesWithCallable((array) $functionLike->stmts, function (Node $node) use ( - &$localReturnNodes - ): ?int { - if ($node instanceof Function_ || $node instanceof Closure || $node instanceof ArrowFunction) { - // skip Return_ nodes in nested functions - return NodeTraverser::DONT_TRAVERSE_CHILDREN; - } - - if (! $node instanceof Return_) { - return null; - } - - // skip void returns - if ($node->expr === null) { - return null; - } - - $localReturnNodes[] = $node; - - return null; - }); - - $types = []; - foreach ($localReturnNodes as $localReturnNode) { - $types = array_merge($types, $this->nodeTypeResolver->resolveSingleTypeToStrings($localReturnNode->expr)); - $this->isVoid = false; - } - - return $types; - } - - /** - * @param ClassMethod|Function_|Closure $functionLike - * @return string[] - */ - private function resolveFromYieldNodes(FunctionLike $functionLike): array - { - /** @var Yield_[] $yieldNodes */ - $yieldNodes = $this->betterNodeFinder->findInstanceOf((array) $functionLike->stmts, Yield_::class); - - $types = []; - if (count($yieldNodes)) { - $this->isVoid = false; - - foreach ($yieldNodes as $yieldNode) { - if ($yieldNode->value === null) { - continue; - } - - $resolvedTypes = $this->nodeTypeResolver->resolveSingleTypeToStrings($yieldNode->value); - foreach ($resolvedTypes as $resolvedType) { - $types[] = $resolvedType . '[]'; - } - } - - if ($this->phpVersionProvider->isAtLeast('7.1')) { - // @see https://www.php.net/manual/en/language.types.iterable.php - $types[] = 'iterable'; - } else { - $types[] = Iterator::class; - } - } - - return array_unique($types); - } }