Skip to content

Commit 1eaef04

Browse files
committed
PHP does not cache is_dir() and similar function values for nonexistent files
1 parent f6107ad commit 1eaef04

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

src/Analyser/MutatingScope.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3477,6 +3477,17 @@ public function specifyExpressionType(Expr $expr, Type $type, ?Type $nativeType
34773477
}
34783478
}
34793479

3480+
if ($expr instanceof FuncCall && $expr->name instanceof Name && $type instanceof ConstantBooleanType && !$type->getValue()) {
3481+
$functionName = $this->reflectionProvider->resolveFunctionName($expr->name, $this);
3482+
if ($functionName !== null && in_array(strtolower($functionName), [
3483+
'is_dir',
3484+
'is_file',
3485+
'file_exists',
3486+
], true)) {
3487+
return $this;
3488+
}
3489+
}
3490+
34803491
return $scope->addMoreSpecificTypes([
34813492
$exprString => $type,
34823493
]);

tests/PHPStan/Analyser/NodeScopeResolverTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ public function dataFileAsserts(): iterable
388388
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4879.php');
389389
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4820.php');
390390
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4822.php');
391+
yield from $this->gatherAssertTypes(__DIR__ . '/data/bug-4816.php');
391392
}
392393

393394
/**
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
namespace Bug4816;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
function (): void {
8+
if (is_dir('foo')) {
9+
assertType('true', is_dir('foo'));
10+
assertType('bool', is_dir('bar'));
11+
12+
clearstatcache();
13+
14+
assertType('bool', is_dir('foo'));
15+
assertType('bool', is_dir('bar'));
16+
}
17+
};
18+
19+
function (): void {
20+
if (!is_dir('foo')) {
21+
assertType('bool', is_dir('foo'));
22+
assertType('bool', is_dir('bar'));
23+
}
24+
};
25+
26+
function (): void {
27+
if (!is_dir('foo')) {
28+
return;
29+
}
30+
31+
assertType('true', is_dir('foo'));
32+
assertType('bool', is_dir('bar'));
33+
34+
clearstatcache();
35+
36+
assertType('bool', is_dir('foo'));
37+
assertType('bool', is_dir('bar'));
38+
};
39+
40+
function (): void {
41+
if (is_dir('foo')) {
42+
return;
43+
}
44+
45+
assertType('bool', is_dir('foo'));
46+
assertType('bool', is_dir('bar'));
47+
};

0 commit comments

Comments
 (0)