33namespace PHPStan \Type \Php ;
44
55use PHPStan \DependencyInjection \AutowiredService ;
6+ use PHPStan \Reflection \ReflectionProvider ;
67use PHPStan \Type \ClassStringType ;
78use PHPStan \Type \Constant \ConstantStringType ;
89use PHPStan \Type \Generic \GenericClassStringType ;
2223final class IsAFunctionTypeSpecifyingHelper
2324{
2425
26+ public function __construct (
27+ private ReflectionProvider $ reflectionProvider ,
28+ )
29+ {
30+ }
31+
2532 public function determineType (
2633 Type $ objectOrClassType ,
2734 Type $ classType ,
@@ -38,16 +45,18 @@ public function determineType(
3845 }
3946
4047 $ isUncertain = $ classType ->getConstantStrings () === [];
48+ $ reflectionProvider = $ this ->reflectionProvider ;
4149
4250 $ resultType = TypeTraverser::map (
4351 $ classType ,
44- static function (Type $ type , callable $ traverse ) use ($ objectOrClassType , $ objectOrClassTypeClassNames , $ allowString , $ allowSameClass , &$ isUncertain ): Type {
52+ static function (Type $ type , callable $ traverse ) use ($ reflectionProvider , $ objectOrClassType , $ objectOrClassTypeClassNames , $ allowString , $ allowSameClass , &$ isUncertain ): Type {
4553 if ($ type instanceof UnionType || $ type instanceof IntersectionType) {
4654 return $ traverse ($ type );
4755 }
4856 if ($ type instanceof ConstantStringType) {
57+ $ typeValue = $ type ->getValue ();
4958 if (!$ allowSameClass ) {
50- if ($ objectOrClassTypeClassNames === [$ type -> getValue () ]) {
59+ if ($ objectOrClassTypeClassNames === [$ typeValue ]) {
5160 $ isSameClass = true ;
5261 foreach ($ objectOrClassType ->getObjectClassReflections () as $ classReflection ) {
5362 if (!$ classReflection ->isFinal ()) {
@@ -63,10 +72,20 @@ static function (Type $type, callable $traverse) use ($objectOrClassType, $objec
6372
6473 if (
6574 // For object, as soon as the exact same type is provided
66- // in the list we cannot be sure of the result
67- in_array ($ type ->getValue (), $ objectOrClassTypeClassNames , true )
75+ // in the list we cannot be sure of the result except for interfaces
76+ (
77+ in_array ($ typeValue , $ objectOrClassTypeClassNames , true )
78+ && (
79+ !$ reflectionProvider ->hasClass ($ typeValue )
80+ || !$ reflectionProvider ->getClass ($ typeValue )->isInterface ()
81+ )
82+ )
6883 // This also occurs for generic class string
69- || ($ allowString && $ objectOrClassTypeClassNames === [] && $ objectOrClassType ->isSuperTypeOf ($ type )->yes ())
84+ || (
85+ $ allowString
86+ && $ objectOrClassTypeClassNames === []
87+ && $ objectOrClassType ->isSuperTypeOf ($ type )->yes ()
88+ )
7089 ) {
7190 $ isUncertain = true ;
7291 }
0 commit comments