Skip to content

Fix phpstan/phpstan#13920: Anonymous class causes "variable might not be defined" issue#5205

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-oi90985
Open

Fix phpstan/phpstan#13920: Anonymous class causes "variable might not be defined" issue#5205
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-oi90985

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When an anonymous class with an explicit constructor calling parent::__construct() was used inside a try block, PHPStan incorrectly reported that variables defined before the try block "might not be defined" in the finally block.

Changes

  • Modified src/Analyser/ExprHandler/NewHandler.php to replace the scope on throw points extracted from the anonymous class constructor's statement result with the outer scope (the scope at the new expression site)
  • Added replaceScope() method to src/Analyser/InternalThrowPoint.php
  • Added regression test in tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php and tests/PHPStan/Rules/Variables/data/bug-13920.php

Root cause

When processing new class() extends Foo { public function __construct() { parent::__construct(); } }, the NewHandler extracted throw points from the constructor's body analysis. These throw points carried scopes from within the constructor method, which naturally didn't contain the outer method's variables. When the try/finally handling merged these throw point scopes into the finallyScope via mergeWith(), any outer variable present in the finally scope but absent from the inner constructor scope was downgraded from "definitely defined" (Yes certainty) to "might not be defined" (Maybe certainty).

The fix replaces the inner scope on these throw points with the outer $scope at the call site, matching the behavior already used for inherited constructors (the else branch at line 196, which uses getConstructorThrowPoint() with the outer scope).

Test

Added a regression test that verifies no errors are reported when a variable is defined before a try block containing an anonymous class with parent::__construct(), and that variable is used in the finally block.

Fixes phpstan/phpstan#13920

- Throw points from anonymous class constructor body carried inner method scopes
  instead of the outer scope, causing variables defined before try blocks to be
  reported as "might not be defined" in finally blocks
- Added replaceScope() method to InternalThrowPoint to allow scope replacement
- New regression test in tests/PHPStan/Rules/Variables/data/bug-13920.php

Closes phpstan/phpstan#13920
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant