From 6159843e047b571c709951e52ce11fb8f349a646 Mon Sep 17 00:00:00 2001 From: Nicolai Ehrhardt <245527909+predictor2718@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:39:02 +0200 Subject: [PATCH 1/3] Fix phpstan/phpstan#13539: property.notFound in chained isset() with checkDynamicProperties --- .../Properties/AccessPropertiesCheck.php | 4 +++ .../Properties/AccessPropertiesRuleTest.php | 14 ++++++++++ .../Rules/Properties/data/bug-13539.php | 28 +++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 tests/PHPStan/Rules/Properties/data/bug-13539.php diff --git a/src/Rules/Properties/AccessPropertiesCheck.php b/src/Rules/Properties/AccessPropertiesCheck.php index b1e0514e8e3..05402130386 100644 --- a/src/Rules/Properties/AccessPropertiesCheck.php +++ b/src/Rules/Properties/AccessPropertiesCheck.php @@ -144,6 +144,10 @@ private function processSingleProperty(Scope $scope, PropertyFetch $node, string if ($maybePropertyReflection !== null && $maybePropertyReflection->isDummy()->no()) { return []; } + + if ($type->getObjectClassNames() === []) { + return []; + } } } diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php index eeda2fb9222..266cd5450a5 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php @@ -1272,4 +1272,18 @@ public function testBug13537(): void $this->analyse([__DIR__ . '/data/bug-13537.php'], $errors); } + public function testBug13539(): void + { + $this->checkThisOnly = false; + $this->checkUnionTypes = true; + $this->checkDynamicProperties = true; + $this->analyse([__DIR__ . '/data/bug-13539.php'], [ + [ + 'Access to an undefined property object::$baz.', + 26, + 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property', + ], + ]); + } + } diff --git a/tests/PHPStan/Rules/Properties/data/bug-13539.php b/tests/PHPStan/Rules/Properties/data/bug-13539.php new file mode 100644 index 00000000000..f55319aa343 --- /dev/null +++ b/tests/PHPStan/Rules/Properties/data/bug-13539.php @@ -0,0 +1,28 @@ +foo) || !isset($tmp->bar)) { + } +} + +function works(string $x): void { + $tmp = json_decode($x, false); + if (!isset($tmp->foo, $tmp->bar)) { + } +} + +function works_too(string $x): void { + /** @var stdClass $tmp */ + $tmp = json_decode($x, false); + if (!isset($tmp->foo) || !isset($tmp->bar)) { + } +} + +function also_ok(mixed $tmp): void { + if (isset($tmp->foo) && isset($tmp->bar)) { + echo $tmp->foo; + echo $tmp->bar; + echo $tmp->baz; // intentional: baz not checked by isset + } +} From 034a1a36cc47bdff38b64aceec6ab5d6b8024d71 Mon Sep 17 00:00:00 2001 From: Nicolai Ehrhardt <245527909+predictor2718@users.noreply.github.com> Date: Tue, 28 Apr 2026 21:58:15 +0200 Subject: [PATCH 2/3] Update testBug13529 to expect no errors after fix for #13539 --- .../Analyser/AnalyserWithCheckDynamicPropertiesTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/PHPStan/Analyser/AnalyserWithCheckDynamicPropertiesTest.php b/tests/PHPStan/Analyser/AnalyserWithCheckDynamicPropertiesTest.php index b6a160de932..5538225e419 100644 --- a/tests/PHPStan/Analyser/AnalyserWithCheckDynamicPropertiesTest.php +++ b/tests/PHPStan/Analyser/AnalyserWithCheckDynamicPropertiesTest.php @@ -12,9 +12,7 @@ class AnalyserWithCheckDynamicPropertiesTest extends PHPStanTestCase public function testBug13529(): void { $errors = $this->runAnalyse(__DIR__ . '/data/bug-13529.php'); - $this->assertCount(1, $errors); - $this->assertSame('Access to an undefined property object::$bar.', $errors[0]->getMessage()); - $this->assertSame(8, $errors[0]->getLine()); + $this->assertCount(0, $errors); } /** From 4f11c353eca710d8021b9c0647d4333086601d8e Mon Sep 17 00:00:00 2001 From: Nicolai Ehrhardt <245527909+predictor2718@users.noreply.github.com> Date: Tue, 28 Apr 2026 22:02:52 +0200 Subject: [PATCH 3/3] Fix bug-13539 test for PHP 7.4 compatibility (use PHPDoc instead of native mixed) --- tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php | 2 +- tests/PHPStan/Rules/Properties/data/bug-13539.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php index 266cd5450a5..674dd0beb77 100644 --- a/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php +++ b/tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php @@ -1280,7 +1280,7 @@ public function testBug13539(): void $this->analyse([__DIR__ . '/data/bug-13539.php'], [ [ 'Access to an undefined property object::$baz.', - 26, + 29, 'Learn more: https://phpstan.org/blog/solving-phpstan-access-to-undefined-property', ], ]); diff --git a/tests/PHPStan/Rules/Properties/data/bug-13539.php b/tests/PHPStan/Rules/Properties/data/bug-13539.php index f55319aa343..845c927a48c 100644 --- a/tests/PHPStan/Rules/Properties/data/bug-13539.php +++ b/tests/PHPStan/Rules/Properties/data/bug-13539.php @@ -19,7 +19,10 @@ function works_too(string $x): void { } } -function also_ok(mixed $tmp): void { +/** + * @param mixed $tmp + */ +function also_ok($tmp): void { if (isset($tmp->foo) && isset($tmp->bar)) { echo $tmp->foo; echo $tmp->bar;