fix: skip StaticCallToMethodCallRector when parent declares final __construct#8001
Merged
Conversation
…onstruct When the nearest ancestor constructor is `final`, PHP forbids declaring any `__construct` in the child class. Previously the rector cloned the parent's `final __construct` and inserted it into the child, producing "Cannot override final method ParentClass::__construct()". Add `ClassDependencyManipulator::hasFinalParentConstructor()` to detect this condition. `FuncCallStaticCallToMethodCallAnalyzer::matchTypeProvidingExpr()` now returns `null` (and its return type is widened to include `null`) when constructor injection is blocked by a final parent constructor. Both `StaticCallToMethodCallRector` and `FuncCallToMethodCallRector` skip the transformation when `null` is returned. Fixes #9766 https://claude.ai/code/session_019aUU1dheeuij6J55RBaYdZ
Member
Author
|
LGTM 👌 |
samsonasik
reviewed
May 21, 2026
| continue; | ||
| } | ||
|
|
||
| $parentClass = $this->astResolver->resolveClassFromClassReflection($ancestor); |
Member
There was a problem hiding this comment.
this should be not needed, there is $ancestor->getNativeMethod(MethodName::CONSTRUCT)->isFinalByKeyword()->yes() for it, see
Member
There was a problem hiding this comment.
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.
Summary
Fixes #9766 (reported in rectorphp/rector).
StaticCallToMethodCallRectortriggered a PHP fatal error when the parent class declared__constructasfinal:The rule was cloning the parent's
final __constructand inserting it into the child class to perform constructor injection — but PHP forbids any__constructoverride when the parent's isfinal(unlikeprivate, where a fresh child constructor is still valid PHP).Changes
ClassDependencyManipulator— addhasFinalParentConstructor(Class_): walks the ancestor chain and returnstruewhen the nearest constructor isfinaland the class has no own constructor.FuncCallStaticCallToMethodCallAnalyzer::matchTypeProvidingExpr()— widen return type to… | null; returnnullwhenhasFinalParentConstructor()is true so the caller can skip the transformation.StaticCallToMethodCallRectorandFuncCallToMethodCallRector— handlenullreturn by leaving the node unchanged (no$hasChanged = true).skip_when_parent_has_final_construct.php.inc(no-----= expects no change) + source classResourceWithFinalConstructwithfinal public function __construct.Test plan
vendor/bin/phpunit rules-tests/Transform/Rector/StaticCall/StaticCallToMethodCallRector/StaticCallToMethodCallRectorTest.php— new fixture asserts code is left unchanged; existing fixtures (public parent, private parent, no parent) still pass.vendor/bin/phpunit rules-tests/Transform/Rector/FuncCall/FuncCallToMethodCallRector/— no regressions in the sibling rector.