Fix #12253: assign.readOnlyProperty#5061
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Open
Conversation
…led from constructor When a constructor calls a helper method that assigns a readonly property and also calls other methods, the property was incorrectly reported as "already assigned". Two root causes: 1. In getMethodsCalledFromConstructor(), non-__construct methods that called other methods had all constructor-initialized properties marked as Yes. This was intended only for additional constructors (like setUp) but incorrectly applied to regular helper methods. Fixed by tracking which methods are original constructors vs discovered helper methods. 2. The additionalAssigns check used scope's hasExpressionType() for PropertyInitializationExpr, but this expression leaks from the constructor scope into all non-static method scopes via rememberConstructorScope(). For non-constructor methods, the scope check always returns Yes even for the first assignment. Fixed by only consulting the scope for __construct itself, and relying on the initializedPropertiesMap for other methods. Fixes phpstan/phpstan#12253
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes phpstan/phpstan#12253 - a false positive
assign.readOnlyPropertyerror when a readonly property is assigned in a method called from the constructor that also calls other methods.Reproducer
Root causes
Two issues in
ClassPropertiesNode::getUninitializedProperties():getMethodsCalledFromConstructor()over-eagerly marks properties as initialized: When a non-__constructmethod (likeparseValidation) calls another method (likevalidationValue), all properties initialized in the constructor were marked asYesfor that method. This logic was intended only for additional constructors configured viaConstructorsHelper(e.g.,setUp), but it applied to all non-__constructmethods. Fixed by passing and checking the list of original constructors.Scope pollution for
PropertyInitializationExpr: TheadditionalAssignscheck consulted$usageScope->hasExpressionType(PropertyInitializationExpr), butPropertyInitializationExprtypes leak from the post-constructor class scope into all non-static method scopes viarememberConstructorScope()+enterFunctionLike($preserveConstructorScope=true). For non-constructor methods, this always reports the property as already initialized even on first assignment. Fixed by only consulting the scope for__constructitself, relying on$initializedPropertiesMapfor helper methods.Changes
src/Node/ClassPropertiesNode.php: Added$originalConstructorsparameter togetMethodsCalledFromConstructor()and restricted both the constructor-property-initialization logic and the scope check to appropriate methodstests/PHPStan/Rules/Properties/data/bug-12253.php: Regression testtests/PHPStan/Rules/Properties/MissingReadOnlyPropertyAssignRuleTest.php: Test method for the regression test