Skip to content

Commit 7efb94b

Browse files
phpstan-botclaude
andcommitted
Do not carry forward method call types into closure scope
Objects are always references in PHP, even when captured by value via `use`. Method return values can change if object state changes between closure definition and invocation. Skip MethodCall expressions (in addition to PropertyFetch) when entering closure scope. Add regression test for method call narrowing with getter/setter pattern. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 89f6e93 commit 7efb94b

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

src/Analyser/MutatingScope.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2152,7 +2152,7 @@ public function enterAnonymousFunctionWithoutReflection(
21522152
}
21532153
}
21542154

2155-
if ($expr instanceof PropertyFetch) {
2155+
if ($expr instanceof PropertyFetch || $expr instanceof MethodCall) {
21562156
continue;
21572157
}
21582158

tests/PHPStan/Rules/Arrays/data/bug-10345.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,32 @@ class Foo {
3030
$container2->items[] = '1';
3131

3232
$a2 = $func2();
33+
34+
class Bar {
35+
/** @var list<string> */
36+
private array $items = [];
37+
38+
/** @return list<string> */
39+
public function getItems(): array
40+
{
41+
return $this->items;
42+
}
43+
44+
/** @param list<string> $items */
45+
public function setItems(array $items): void
46+
{
47+
$this->items = $items;
48+
}
49+
}
50+
51+
$container3 = new Bar();
52+
if ($container3->getItems() === []) {
53+
$func3 = function() use ($container3): int {
54+
foreach ($container3->getItems() as $item) {}
55+
return 1;
56+
};
57+
58+
$container3->setItems(['foo']);
59+
60+
$a3 = $func3();
61+
}

0 commit comments

Comments
 (0)