41
41
/**
42
42
* @implements Rule<Foreach_>
43
43
*/
44
- final class UnsafeForeachArrayOfStringRule implements Rule{
44
+ final class UnsafeForeachRule implements Rule{
45
45
46
46
public function getNodeType () : string {
47
47
return Foreach_::class;
@@ -73,7 +73,7 @@ public function processNode(Node $node, Scope $scope) : array{
73
73
$ benevolentUnionDepth --;
74
74
return $ result ;
75
75
}
76
- if ($ type instanceof IntegerType && $ benevolentUnionDepth === 0 ){
76
+ if ($ type instanceof IntegerType){
77
77
$ expectsIntKeyTypes = true ;
78
78
return $ type ;
79
79
}
@@ -87,24 +87,31 @@ public function processNode(Node $node, Scope $scope) : array{
87
87
$ hasCastableKeyTypes = true ;
88
88
return $ type ;
89
89
});
90
- if ($ hasCastableKeyTypes && !$ expectsIntKeyTypes ){
91
- $ tip = $ implicitType ?
92
- sprintf (
93
- "Declare a key type using @phpstan-var or @phpstan-param, or use %s() to promote the key type to get proper error reporting " ,
90
+ $ errors = [];
91
+ if ($ implicitType ){
92
+ $ errors [] = RuleErrorBuilder::message ("Possible unreported errors in foreach on array with unspecified key type. " )
93
+ ->tip (sprintf (
94
+ <<<TIP
95
+ PHPStan might not be reporting some type errors if the key type is not specified.
96
+ Declare a key type using @phpstan-var or @phpstan-param, or use %s() to force PHPStan to report proper errors.
97
+ TIP ,
94
98
Utils::getNiceClosureName (Utils::promoteKeys (...))
95
- ) :
96
- sprintf (
97
- "Use %s() to get a \Generator that will force the keys to string " ,
98
- Utils::getNiceClosureName (Utils::stringifyKeys (...)),
99
- );
100
- return [
101
- RuleErrorBuilder::message (sprintf (
102
- "Unsafe foreach on array with key type %s (they might be casted to int). " ,
103
- $ iterableType ->getIterableKeyType ()->describe (VerbosityLevel::value ())
104
- ))->tip ($ tip )->identifier ('pocketmine.foreach.stringKeys ' )->build ()
105
- ];
99
+ ))->identifier ('pocketmine.foreach.implicitKeys ' )->build ();
100
+ }
101
+ if ($ hasCastableKeyTypes && !$ expectsIntKeyTypes ){
102
+ $ errors [] = RuleErrorBuilder::message (sprintf (
103
+ "Unsafe foreach on array with key type %s. " ,
104
+ $ iterableType ->getIterableKeyType ()->describe (VerbosityLevel::value ())
105
+ ))
106
+ ->tip (sprintf (
107
+ <<<TIP
108
+ PHP coerces numeric strings to integers when used as array keys, which can lead to unexpected type errors when passing the key to a function.
109
+ Use %s() to wrap the array in a \Generator that will force the keys back to string during iteration.
110
+ TIP ,
111
+ Utils::getNiceClosureName (Utils::stringifyKeys (...))
112
+ ))->identifier ('pocketmine.foreach.stringKeys ' )->build ();
106
113
}
107
- return [] ;
114
+ return $ errors ;
108
115
}
109
116
110
117
}
0 commit comments