diff --git a/conf/config.neon b/conf/config.neon index e0df3b916fd..f89fc6ebf7f 100644 --- a/conf/config.neon +++ b/conf/config.neon @@ -1438,6 +1438,9 @@ services: tags: - phpstan.typeSpecifier.functionTypeSpecifyingExtension + - + class: PHPStan\Type\Php\IsAFunctionTypeSpecifyingHelper + - class: PHPStan\Type\Php\ArrayIsListFunctionTypeSpecifyingExtension tags: diff --git a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php index 490c8b7b5ae..1220eabab0e 100644 --- a/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsAFunctionTypeSpecifyingExtension.php @@ -9,18 +9,9 @@ use PHPStan\Analyser\TypeSpecifierAwareExtension; use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Type\ClassStringType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\FunctionTypeSpecifyingExtension; -use PHPStan\Type\Generic\GenericClassStringType; -use PHPStan\Type\IntersectionType; -use PHPStan\Type\ObjectType; -use PHPStan\Type\ObjectWithoutClassType; -use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeTraverser; -use PHPStan\Type\UnionType; use function count; use function strtolower; @@ -29,6 +20,12 @@ class IsAFunctionTypeSpecifyingExtension implements FunctionTypeSpecifyingExtens private TypeSpecifier $typeSpecifier; + public function __construct( + private IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper, + ) + { + } + public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { return strtolower($functionReflection->getName()) === 'is_a' @@ -48,40 +45,9 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes([], []); } - $type = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use ($allowString): Type { - if ($type instanceof UnionType || $type instanceof IntersectionType) { - return $traverse($type); - } - if ($type instanceof ConstantStringType) { - if ($allowString) { - return TypeCombinator::union( - new ObjectType($type->getValue()), - new GenericClassStringType(new ObjectType($type->getValue())), - ); - } - return new ObjectType($type->getValue()); - } - if ($type instanceof GenericClassStringType) { - if ($allowString) { - return TypeCombinator::union( - $type->getGenericType(), - $type, - ); - } - return $type->getGenericType(); - } - if ($allowString) { - return TypeCombinator::union( - new ObjectWithoutClassType(), - new ClassStringType(), - ); - } - return new ObjectWithoutClassType(); - }); - return $this->typeSpecifier->create( $node->getArgs()[0]->value, - $type, + $this->isAFunctionTypeSpecifyingHelper->determineType($classType, $allowString), $context, false, $scope, diff --git a/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php b/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php new file mode 100644 index 00000000000..8a689e60530 --- /dev/null +++ b/src/Type/Php/IsAFunctionTypeSpecifyingHelper.php @@ -0,0 +1,62 @@ +getValue()), + new GenericClassStringType(new ObjectType($type->getValue())), + ); + } + + return new ObjectType($type->getValue()); + } + if ($type instanceof GenericClassStringType) { + if ($allowString) { + return TypeCombinator::union( + $type->getGenericType(), + $type, + ); + } + + return $type->getGenericType(); + } + if ($allowString) { + return TypeCombinator::union( + new ObjectWithoutClassType(), + new ClassStringType(), + ); + } + + return new ObjectWithoutClassType(); + }, + ); + } + +} diff --git a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php index c4633421943..15c773784ee 100644 --- a/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php +++ b/src/Type/Php/IsSubclassOfFunctionTypeSpecifyingExtension.php @@ -9,18 +9,9 @@ use PHPStan\Analyser\TypeSpecifierAwareExtension; use PHPStan\Analyser\TypeSpecifierContext; use PHPStan\Reflection\FunctionReflection; -use PHPStan\Type\ClassStringType; use PHPStan\Type\Constant\ConstantBooleanType; use PHPStan\Type\Constant\ConstantStringType; use PHPStan\Type\FunctionTypeSpecifyingExtension; -use PHPStan\Type\Generic\GenericClassStringType; -use PHPStan\Type\IntersectionType; -use PHPStan\Type\ObjectType; -use PHPStan\Type\ObjectWithoutClassType; -use PHPStan\Type\Type; -use PHPStan\Type\TypeCombinator; -use PHPStan\Type\TypeTraverser; -use PHPStan\Type\UnionType; use function count; use function strtolower; @@ -29,6 +20,12 @@ class IsSubclassOfFunctionTypeSpecifyingExtension implements FunctionTypeSpecify private TypeSpecifier $typeSpecifier; + public function __construct( + private IsAFunctionTypeSpecifyingHelper $isAFunctionTypeSpecifyingHelper, + ) + { + } + public function isFunctionSupported(FunctionReflection $functionReflection, FuncCall $node, TypeSpecifierContext $context): bool { return strtolower($functionReflection->getName()) === 'is_subclass_of' @@ -48,40 +45,9 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n return new SpecifiedTypes([], []); } - $type = TypeTraverser::map($classType, static function (Type $type, callable $traverse) use ($allowString): Type { - if ($type instanceof UnionType || $type instanceof IntersectionType) { - return $traverse($type); - } - if ($type instanceof ConstantStringType) { - if ($allowString) { - return TypeCombinator::union( - new ObjectType($type->getValue()), - new GenericClassStringType(new ObjectType($type->getValue())), - ); - } - return new ObjectType($type->getValue()); - } - if ($type instanceof GenericClassStringType) { - if ($allowString) { - return TypeCombinator::union( - $type->getGenericType(), - $type, - ); - } - return $type->getGenericType(); - } - if ($allowString) { - return TypeCombinator::union( - new ObjectWithoutClassType(), - new ClassStringType(), - ); - } - return new ObjectWithoutClassType(); - }); - return $this->typeSpecifier->create( $node->getArgs()[0]->value, - $type, + $this->isAFunctionTypeSpecifyingHelper->determineType($classType, $allowString), $context, false, $scope,