Report new on an expression whose type is not string|object via new.nonObject#5866
Open
phpstan-bot wants to merge 3 commits into
Open
Report new on an expression whose type is not string|object via new.nonObject#5866phpstan-bot wants to merge 3 commits into
new on an expression whose type is not string|object via new.nonObject#5866phpstan-bot wants to merge 3 commits into
Conversation
e237c69 to
57a00e8
Compare
57a00e8 to
d391efd
Compare
d391efd to
9def6e9
Compare
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VincentLanglet
left a comment
Contributor
There was a problem hiding this comment.
This should be behind a flag which is enabled by bleedingEdge
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Collaborator
Author
|
Done. I addressed VincentLanglet's review. What I changedThe reviewer asked that the new
One gotcha worth noting: after adding a new Verification
Committed as |
VincentLanglet
approved these changes
Jun 14, 2026
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
PHPStan did not detect when the
newoperator is used with an expression whose type can never be a valid class name. For examplenew $classwhere$classisintwas silently accepted, even though it always fails at runtime. This PR makesInstantiationRulereport such cases with a newnew.nonObjecterror, mirroring the existing checks for the analogous dynamic-class-name constructs.Changes
src/Rules/Classes/InstantiationRule.phpRuleLevelHelperand addedcheckClassNameExprType(), run fornew $expr(when the class is an expression).findTypeToCheck()against the accepted typestring|object(new UnionType([new StringType(), new ObjectWithoutClassType()])) and reportsCannot instantiate class using <type>.with identifiernew.nonObjectwhen the type is not a supertype-compatiblestring/object.ErrorTyperesults (mixed/never/unknown class) are intentionally skipped so the existingclass.notFound("Instantiated class X not found.") path keeps working for object values of unknown classes.src/Type/Php/Base64DecodeDynamicFunctionReturnTypeExtension.phpbase64_decode()when the input is a constant string, returning the decodedConstantStringType(orfalsein strict mode for invalid base64). The decode always runs in strict mode internally; for a non-strict call on invalid input the extension falls back to the genericstringrather than guessing the lenient result.tests/PHPStan/Rules/Classes/data/instantiation-non-object.php+testInstantiationWithNonObjectType()inInstantiationRuleTest.InstantiationRuletest factories (InstantiationRuleTest,ForbiddenNameCheckExtensionRuleTest) for the new constructor argument.tests/PHPStan/Analyser/nsrt/base64_decode.phpwith constant-input cases and adjusted the constant''expectations intests/PHPStan/Analyser/nsrt/functions.php.Root cause
InstantiationRule::getClassNames()only produced class names from constant strings and object types; for any other expression type it returned an empty list, so no error was ever emitted fornew $wrongType. The fix adds an explicit type check for the expression form ofnew, using the samestring|objectacceptance criterion that the parallel rules already use.Parallel-construct audit (dynamic class name in a class-name context): static method call (
staticMethod.nonObject), static property access (staticProperty.nonObject), class constant fetch (classConstant.nonObject) andinstanceof(instanceof.invalidExprType) already report wrong dynamic class types.newwas the single missing member of that family, now covered.The
base64_decode()constant-folding is required because PHPStan's own source instantiates a base64-obfuscated adapter class name (new $enumAdapter(...)inNodeScopeResolverandBetterReflectionProvider). Without folding, that value isstring|false, which the new rule correctly flags. Folding resolves it to the preciseclass-string, which both satisfies the new rule and lets the surroundingClassReflectionFactory::create()call stay well-typed — i.e. teaching inference rather than rewriting the source.Test
InstantiationRuleTest::testInstantiationWithNonObjectType()assertsnew.nonObjectis reported fornew $int,new $float,new $bool,new $intOrStringandnew $array, and that valid forms (string,class-string,object, an instance) produce no error. Verified the data file produces no errors before the rule change.tests/PHPStan/Analyser/nsrt/base64_decode.phpasserts the new constant-folded return types ('Hello world',false,string).make tests: 17383 tests) andmake phpstanshows no new errors (only pre-existingshipmonk.deadMethodfindings unrelated to this change).Fixes phpstan/phpstan#4922