[Strict] Skip class re-parse for typed default property in UninitializedPropertyAnalyzer#8101
Merged
Merged
Conversation
…zedPropertyAnalyzer A typed property with an explicit default value is always initialized, so empty()/isset() narrowing never applies to it. Detect that case up front via ReflectionProvider and return early, avoiding the heavy AstResolver::resolveClassFromName() parse of the declaring class. The hasType() guard keeps untyped properties (implicit null default) on the existing path, preserving current behaviour.
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.
What
UninitializedPropertyAnalyzer::isUninitialized()resolved the declaring class into a full AST viaAstResolver->resolveClassFromName()for every property fetch, only to then check the property's default and whether it's assigned in the constructor.A typed property with an explicit default (
private array $items = [];) is always initialized — it can never be in an uninitialized state — so the answer isfalsewithout parsing anything. This adds aReflectionProviderfast-path that returns early in that case, before the parse:This is a partial improvement: when the property has no default (or isn't typed), the analyzer still falls through to
AstResolver+ConstructorAssignDetector, because "is this property assigned in the constructor?" is flow analysis that reflection cannot answer. Only the always-initialized case is short-circuited.Why the
hasType()guardAn untyped property (
public $items;) reports an implicitnulldefault —ReflectionProperty::hasDefaultValue()returnstrueeven though there is no explicit= .... Guarding onhasType()keeps untyped properties on the original path so behaviour is unchanged.Tests
Existing fixtures already cover both branches and pass unchanged:
property_with_default_value(typed + default → fast-path)may_uninitialized_property_no_default_value(typed, no default → AST path)Added
skip_untyped_propertyto lock the untyped-property behaviour (left unchanged).vendor/bin/phpunit rules-tests/Strict/Rector/Empty_/DisallowedEmptyRuleFixerRector→ 18/18 green. ECS + full PHPStan level 8 clean.