Skip to content

Commit c70d58c

Browse files
phpstan-botclaude
authored 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 e04acb0 commit c70d58c

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
@@ -2080,7 +2080,7 @@ public function enterAnonymousFunctionWithoutReflection(
20802080
}
20812081
}
20822082

2083-
if ($expr instanceof PropertyFetch) {
2083+
if ($expr instanceof PropertyFetch || $expr instanceof MethodCall) {
20842084
continue;
20852085
}
20862086

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)