Skip to content

Commit a11741d

Browse files
committed
Fix narrowing of superglobals
1 parent 72d2f3b commit a11741d

File tree

6 files changed

+119
-3
lines changed

6 files changed

+119
-3
lines changed

Diff for: src/Analyser/MutatingScope.php

+6-3
Original file line numberDiff line numberDiff line change
@@ -554,10 +554,13 @@ public function getVariableType(string $variableName): Type
554554

555555
$varExprString = '$' . $variableName;
556556
if (!array_key_exists($varExprString, $this->expressionTypes)) {
557-
if ($this->isGlobalVariable($variableName)) {
558-
return new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true));
557+
if (!$this->isGlobalVariable($variableName)) {
558+
return new MixedType();
559559
}
560-
return new MixedType();
560+
561+
$superglobalType = new ArrayType(new BenevolentUnionType([new IntegerType(), new StringType()]), new MixedType(true));
562+
$this->expressionTypes[$varExprString] = ExpressionTypeHolder::createYes(new Variable($variableName), $superglobalType);
563+
$this->nativeExpressionTypes[$varExprString] = ExpressionTypeHolder::createYes(new Variable($variableName), $superglobalType);
561564
}
562565

563566
return TypeUtils::resolveLateResolvableTypes($this->expressionTypes[$varExprString]->getType());

Diff for: tests/PHPStan/Analyser/nsrt/superglobals.php

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Superglobals;
4+
5+
use function PHPStan\Testing\assertNativeType;
6+
use function PHPStan\Testing\assertType;
7+
8+
class Superglobals
9+
{
10+
11+
public function originalTypes(): void
12+
{
13+
assertType('array<mixed>', $GLOBALS);
14+
assertType('array<mixed>', $_SERVER);
15+
assertType('array<mixed>', $_GET);
16+
assertType('array<mixed>', $_POST);
17+
assertType('array<mixed>', $_FILES);
18+
assertType('array<mixed>', $_COOKIE);
19+
assertType('array<mixed>', $_SESSION);
20+
assertType('array<mixed>', $_REQUEST);
21+
assertType('array<mixed>', $_ENV);
22+
}
23+
24+
public function canBeOverwritten(): void
25+
{
26+
$GLOBALS = [];
27+
assertType('array{}', $GLOBALS);
28+
assertNativeType('array{}', $GLOBALS);
29+
}
30+
31+
public function canBePartlyOverwritten(): void
32+
{
33+
$GLOBALS['foo'] = 'foo';
34+
assertType("non-empty-array&hasOffsetValue('foo', 'foo')", $GLOBALS);
35+
assertNativeType("non-empty-array&hasOffsetValue('foo', 'foo')", $GLOBALS);
36+
}
37+
38+
public function canBeNarrowed(): void
39+
{
40+
if (isset($GLOBALS['foo'])) {
41+
assertType("non-empty-array&hasOffsetValue('foo', mixed~null)", $GLOBALS);
42+
assertNativeType("non-empty-array<mixed>&hasOffset('foo')", $GLOBALS); // https://github.com/phpstan/phpstan/issues/8395
43+
} else {
44+
assertType('array<mixed>', $GLOBALS);
45+
assertNativeType('array<mixed>', $GLOBALS);
46+
}
47+
assertType('array', $GLOBALS);
48+
assertNativeType('array<mixed>', $GLOBALS);
49+
}
50+
51+
}
52+
53+
function functionScope() {
54+
assertType('array<mixed>', $GLOBALS);
55+
assertNativeType('array<mixed>', $GLOBALS);
56+
}
57+
58+
assertType('array<mixed>', $GLOBALS);
59+
assertNativeType('array<mixed>', $GLOBALS);

Diff for: tests/PHPStan/Rules/Comparison/StrictComparisonOfDifferentTypesRuleTest.php

+5
Original file line numberDiff line numberDiff line change
@@ -1001,4 +1001,9 @@ public function testHashing(): void
10011001
]);
10021002
}
10031003

1004+
public function testBug12772(): void
1005+
{
1006+
$this->analyse([__DIR__ . '/data/bug-12772.php'], []);
1007+
}
1008+
10041009
}

Diff for: tests/PHPStan/Rules/Comparison/data/bug-12772.php

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug12772;
4+
5+
class HelloWorld
6+
{
7+
public function sayHello(DateTimeImutable $date): void
8+
{
9+
foreach ($tables as $table) {
10+
11+
// If view exists, and 'add drop view' is selected: Drop it!
12+
if ($_POST['what'] !== 'nocopy' && isset($_POST['drop_if_exists']) && $_POST['drop_if_exists'] === 'true') {
13+
14+
}
15+
}
16+
}
17+
}

Diff for: tests/PHPStan/Rules/Variables/IssetRuleTest.php

+7
Original file line numberDiff line numberDiff line change
@@ -473,4 +473,11 @@ public function testBug9328(): void
473473
$this->analyse([__DIR__ . '/data/bug-9328.php'], []);
474474
}
475475

476+
public function testBug12771(): void
477+
{
478+
$this->treatPhpDocTypesAsCertain = true;
479+
480+
$this->analyse([__DIR__ . '/data/bug-12771.php'], []);
481+
}
482+
476483
}

Diff for: tests/PHPStan/Rules/Variables/data/bug-12771.php

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Bug12771;
4+
5+
final class ErrorReportController
6+
{
7+
8+
public function __invoke(ServerRequest $request)
9+
{
10+
if (
11+
isset($_SESSION['prev_error_subm_time'], $_SESSION['error_subm_count'])
12+
&& $_SESSION['error_subm_count'] >= 3
13+
&& ($_SESSION['prev_error_subm_time'] - time()) <= 3000
14+
) {
15+
$_SESSION['error_subm_count'] = 0;
16+
$_SESSION['prev_errors'] = '';
17+
} else {
18+
$_SESSION['prev_error_subm_time'] = time();
19+
$_SESSION['error_subm_count'] = isset($_SESSION['error_subm_count'])
20+
? $_SESSION['error_subm_count'] + 1
21+
: 0;
22+
}
23+
24+
}
25+
}

0 commit comments

Comments
 (0)