66use PHPStan \Analyser \Scope ;
77use PHPStan \DependencyInjection \AutowiredService ;
88use PHPStan \Reflection \FunctionReflection ;
9+ use PHPStan \ShouldNotHappenException ;
910use PHPStan \Type \DynamicFunctionReturnTypeExtension ;
1011use PHPStan \Type \NullType ;
1112use PHPStan \Type \Type ;
@@ -19,7 +20,12 @@ final class ArrayFirstLastDynamicReturnTypeExtension implements DynamicFunctionR
1920
2021 public function isFunctionSupported (FunctionReflection $ functionReflection ): bool
2122 {
22- return in_array ($ functionReflection ->getName (), ['array_first ' , 'array_last ' ], true );
23+ return in_array ($ functionReflection ->getName (), [
24+ 'array_key_first ' ,
25+ 'array_key_last ' ,
26+ 'array_first ' ,
27+ 'array_last ' ,
28+ ], true );
2329 }
2430
2531 public function getTypeFromFunctionCall (FunctionReflection $ functionReflection , FuncCall $ functionCall , Scope $ scope ): ?Type
@@ -37,13 +43,17 @@ public function getTypeFromFunctionCall(FunctionReflection $functionReflection,
3743 return new NullType ();
3844 }
3945
40- $ valueType = $ argType ->getIterableValueType ();
46+ $ resultType = match ($ functionReflection ->getName ()) {
47+ 'array_key_first ' , 'array_key_last ' => $ argType ->getIterableKeyType (),
48+ 'array_first ' , 'array_last ' => $ argType ->getIterableValueType (),
49+ default => throw new ShouldNotHappenException (),
50+ };
4151
4252 if ($ iterableAtLeastOnce ->yes ()) {
43- return $ valueType ;
53+ return $ resultType ;
4454 }
4555
46- return TypeCombinator::union ($ valueType , new NullType ());
56+ return TypeCombinator::union ($ resultType , new NullType ());
4757 }
4858
4959}
0 commit comments