Skip to content

Commit 8613169

Browse files
committed
array_key_exists - fix for AST-based offset
1 parent 1ac71f9 commit 8613169

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed

src/Type/Php/ArrayKeyExistsFunctionTypeSpecifyingExtension.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22

33
namespace PHPStan\Type\Php;
44

5+
use PhpParser\Node\Expr\ArrayDimFetch;
6+
use PhpParser\Node\Expr\BinaryOp\Identical;
7+
use PhpParser\Node\Expr\ConstFetch;
58
use PhpParser\Node\Expr\FuncCall;
9+
use PhpParser\Node\Name;
610
use PHPStan\Analyser\Scope;
711
use PHPStan\Analyser\SpecifiedTypes;
812
use PHPStan\Analyser\TypeSpecifier;
@@ -48,8 +52,18 @@ public function specifyTypes(
4852
if (count($node->getArgs()) < 2) {
4953
return new SpecifiedTypes();
5054
}
51-
$keyType = $scope->getType($node->getArgs()[0]->value);
55+
$key = $node->getArgs()[0]->value;
56+
$array = $node->getArgs()[1]->value;
57+
$keyType = $scope->getType($key);
5258
if (!$keyType instanceof ConstantIntegerType && !$keyType instanceof ConstantStringType) {
59+
if ($context->truthy()) {
60+
$arrayDimFetch = new ArrayDimFetch(
61+
$array,
62+
$key,
63+
);
64+
return $this->typeSpecifier->create($arrayDimFetch, $scope->getType($array)->getIterableValueType(), $context, false, $scope, new Identical($arrayDimFetch, new ConstFetch(new Name('__PHPSTAN_FAUX_CONSTANT'))));
65+
}
66+
5367
return new SpecifiedTypes();
5468
}
5569

@@ -63,7 +77,7 @@ public function specifyTypes(
6377
}
6478

6579
return $this->typeSpecifier->create(
66-
$node->getArgs()[1]->value,
80+
$array,
6781
$type,
6882
$context,
6983
false,

tests/PHPStan/Rules/Arrays/NonexistentOffsetInArrayDimFetchRuleTest.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,4 +499,13 @@ public function testBug7469(): void
499499
$this->analyse([__DIR__ . '/data/bug-7469.php'], $expected);
500500
}
501501

502+
public function testBug7763(): void
503+
{
504+
if (PHP_VERSION_ID < 80100) {
505+
$this->markTestSkipped('Test requires PHP 8.1.');
506+
}
507+
508+
$this->analyse([__DIR__ . '/data/bug-7763.php'], []);
509+
}
510+
502511
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php // lint >= 8.1
2+
3+
namespace Bug7763;
4+
5+
enum MyEnum: int {
6+
case Case1 = 1;
7+
case Case2 = 2;
8+
9+
public function test(self $enum): string
10+
{
11+
$mapping = array_filter([
12+
self::Case1->value => $this->maybeNull(),
13+
self::Case2->value => $this->maybeNull(),
14+
]);
15+
16+
if (array_key_exists($enum->value, $mapping)) {
17+
return $mapping[$enum->value]; // Offset 1|2 does not exist on array{1?: non-falsy-string, 2?: non-falsy-string}
18+
}
19+
20+
return '';
21+
}
22+
23+
private function maybeNull(): ?string
24+
{
25+
return (bool) rand(0, 1) ? '' : null;
26+
}
27+
}

0 commit comments

Comments
 (0)