16
16
use PHPStan \Type \IterableType ;
17
17
use PHPStan \Type \MixedType ;
18
18
use PHPStan \Type \NullType ;
19
+ use PHPStan \Type \ObjectWithoutClassType ;
19
20
use PHPStan \Type \Type ;
20
21
use PHPStan \Type \TypeCombinator ;
22
+ use PHPStan \Type \TypeTraverser ;
21
23
use PHPStan \Type \VoidType ;
22
24
23
25
final class QueryResultDynamicReturnTypeExtension implements DynamicMethodReturnTypeExtension
@@ -109,12 +111,20 @@ private function getMethodReturnTypeForHydrationMode(
109
111
return $ this ->originalReturnType ($ methodReflection );
110
112
}
111
113
112
- if (!$ this ->isObjectHydrationMode ($ hydrationMode )) {
113
- // We support only HYDRATE_OBJECT. For other hydration modes, we
114
- // return the declared return type of the method.
114
+ if (!$ hydrationMode instanceof ConstantIntegerType) {
115
115
return $ this ->originalReturnType ($ methodReflection );
116
116
}
117
117
118
+ switch ($ hydrationMode ->getValue ()) {
119
+ case AbstractQuery::HYDRATE_OBJECT ;
120
+ break ;
121
+ case AbstractQuery::HYDRATE_ARRAY ;
122
+ $ queryResultType = $ this ->getArrayHydratedReturnType ($ queryResultType );
123
+ break ;
124
+ default :
125
+ return $ this ->originalReturnType ($ methodReflection );
126
+ }
127
+
118
128
switch ($ methodReflection ->getName ()) {
119
129
case 'getSingleResult ' :
120
130
return $ queryResultType ;
@@ -133,13 +143,22 @@ private function getMethodReturnTypeForHydrationMode(
133
143
}
134
144
}
135
145
136
- private function isObjectHydrationMode (Type $ type ): bool
146
+ private function getArrayHydratedReturnType (Type $ queryResultType ): Type
137
147
{
138
- if (!$ type instanceof ConstantIntegerType) {
139
- return false ;
140
- }
141
-
142
- return $ type ->getValue () === AbstractQuery::HYDRATE_OBJECT ;
148
+ return TypeTraverser::map (
149
+ $ queryResultType ,
150
+ static function (Type $ type , callable $ traverse ): Type {
151
+ $ isObject = (new ObjectWithoutClassType ())->isSuperTypeOf ($ type );
152
+ if ($ isObject ->yes ()) {
153
+ return new ArrayType (new MixedType (), new MixedType ());
154
+ }
155
+ if ($ isObject ->maybe ()) {
156
+ return new MixedType ();
157
+ }
158
+
159
+ return $ traverse ($ type );
160
+ }
161
+ );
143
162
}
144
163
145
164
private function originalReturnType (MethodReflection $ methodReflection ): Type
0 commit comments