Skip to content

Commit a2ae368

Browse files
committed
Fix phpstan/phpstan#14241: Report error for auto-global variable in parameters
- Added SuperGlobalParameterRule to detect superglobal variable names used as function/method/closure parameters - PHP throws a fatal error for this (e.g. `function doFoo($_FILES): void {}`), but PHPStan was not reporting it - New regression test in tests/PHPStan/Rules/Functions/data/bug-14241.php - Excluded test data file from Makefile lint step since PHP cannot parse files with superglobal parameters
1 parent a275ce9 commit a2ae368

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ lint:
127127
--exclude tests/PHPStan/Rules/Properties/data/override-attr-on-property.php \
128128
--exclude tests/PHPStan/Rules/Properties/data/property-override-attr.php \
129129
--exclude tests/PHPStan/Rules/Operators/data/bug-3585.php \
130+
--exclude tests/PHPStan/Rules/Functions/data/bug-14241.php \
130131
src tests
131132

132133
install-paratest:
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Functions;
4+
5+
use PhpParser\Node;
6+
use PHPStan\Analyser\Scope;
7+
use PHPStan\DependencyInjection\RegisteredRule;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Rules\RuleErrorBuilder;
10+
use function in_array;
11+
use function is_string;
12+
use function sprintf;
13+
14+
/**
15+
* @implements Rule<Node\FunctionLike>
16+
*/
17+
#[RegisteredRule(level: 0)]
18+
final class SuperGlobalParameterRule implements Rule
19+
{
20+
21+
public function getNodeType(): string
22+
{
23+
return Node\FunctionLike::class;
24+
}
25+
26+
public function processNode(Node $node, Scope $scope): array
27+
{
28+
$errors = [];
29+
30+
foreach ($node->getParams() as $param) {
31+
if (!$param->var instanceof Node\Expr\Variable) {
32+
continue;
33+
}
34+
35+
if (!is_string($param->var->name)) {
36+
continue;
37+
}
38+
39+
$var = $param->var->name;
40+
41+
if (!in_array($var, Scope::SUPERGLOBAL_VARIABLES, true)) {
42+
continue;
43+
}
44+
45+
$errors[] = RuleErrorBuilder::message(sprintf('Cannot re-assign auto-global variable $%s.', $var))
46+
->line($param->getStartLine())
47+
->identifier('parameter.superGlobal')
48+
->nonIgnorable()
49+
->build();
50+
}
51+
52+
return $errors;
53+
}
54+
55+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace PHPStan\Rules\Functions;
4+
5+
use PHPStan\Rules\Rule;
6+
use PHPStan\Testing\RuleTestCase;
7+
8+
/**
9+
* @extends RuleTestCase<SuperGlobalParameterRule>
10+
*/
11+
class SuperGlobalParameterRuleTest extends RuleTestCase
12+
{
13+
14+
protected function getRule(): Rule
15+
{
16+
return new SuperGlobalParameterRule();
17+
}
18+
19+
public function testRule(): void
20+
{
21+
$this->analyse([__DIR__ . '/data/bug-14241.php'], [
22+
[
23+
'Cannot re-assign auto-global variable $_FILES.',
24+
5,
25+
],
26+
[
27+
'Cannot re-assign auto-global variable $_GET.',
28+
7,
29+
],
30+
[
31+
'Cannot re-assign auto-global variable $_POST.',
32+
7,
33+
],
34+
[
35+
'Cannot re-assign auto-global variable $_SERVER.',
36+
13,
37+
],
38+
[
39+
'Cannot re-assign auto-global variable $_SESSION.',
40+
15,
41+
],
42+
[
43+
'Cannot re-assign auto-global variable $_COOKIE.',
44+
18,
45+
],
46+
[
47+
'Cannot re-assign auto-global variable $_REQUEST.',
48+
20,
49+
],
50+
[
51+
'Cannot re-assign auto-global variable $_ENV.',
52+
22,
53+
],
54+
[
55+
'Cannot re-assign auto-global variable $GLOBALS.',
56+
24,
57+
],
58+
]);
59+
}
60+
61+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug14241;
4+
5+
function doFoo($_FILES): void {}
6+
7+
function doBar($_GET, $_POST): void {}
8+
9+
function doBaz($ok): void {}
10+
11+
class Foo
12+
{
13+
public function doFoo($_SERVER): void {}
14+
15+
public static function doBar($_SESSION): void {}
16+
}
17+
18+
$f = function ($_COOKIE): void {};
19+
20+
$g = fn ($_REQUEST) => $_REQUEST;
21+
22+
function doQux($_ENV): void {}
23+
24+
function doQuux($GLOBALS): void {}

0 commit comments

Comments
 (0)