Check all interfaces instead of only immediate ones for constructor enforcement in NewStaticRule#5740
Open
phpstan-bot wants to merge 2 commits into
Open
Conversation
…nforcement in `NewStaticRule` - Change `getImmediateInterfaces()` to `getInterfaces()` in `NewStaticRule::processNode()` so that constructor-defining interfaces inherited from parent classes are found when determining whether `new static()` is safe. - Add regression test covering the reported hierarchy (class -> abstract -> abstract implementing interface -> concrete) and a deeply-nested variant.
VincentLanglet
approved these changes
May 23, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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
When a class uses
new static()and an interface enforces the constructor signature, PHPStan should consider the usage safe. However, when the interface was implemented by a parent class rather than the class itself, PHPStan incorrectly reported "Unsafe usage of new static()." because it only checked immediate interfaces.Changes
$classReflection->getImmediateInterfaces()to$classReflection->getInterfaces()insrc/Rules/Classes/NewStaticRule.php(line 72) so the rule traverses the full interface hierarchy when looking for constructor-defining interfaces.Root cause
NewStaticRulehas two checks for interface-enforced constructors:Check 1 fails when a concrete parent class also defines the constructor (the prototype points to the class, not the interface). Check 2 was the fallback, but it used
getImmediateInterfaces()which only returns interfaces directly implemented by the current class — missing interfaces inherited from parent classes.Analogous cases probed
NewStaticInAbstractClassStaticMethodRule: different concern (abstract class instantiation), does not check interfaces for constructor enforcement — not affected.MethodPrototypeFinder::findPrototype(): usesgetImmediateInterfaces()correctly because it does its own manual hierarchy walk viagetParentClass().OverridingConstantRule::findPrototype(): same as above — manual hierarchy walk, correct usage.AllowedSubTypesRule: intentionally checks only direct parents for allowed subtypes — correct usage.Test
Added
tests/PHPStan/Rules/Classes/data/bug-10274.phpwith:AbstractArray(concrete constructor) ->AbstractCollection->IntermediateCollection implements ConstructorDefiningInterface->SpecificCollectionusingnew static().DeeplyNestedCollection extends SpecificCollection) to verify the fix works at arbitrary depth.Both cases expect no errors (empty expected-errors array).
Fixes phpstan/phpstan#10274