Skip to content

Fix phpstan/phpstan#14102: No error if construct signature of class-string of abstract class is invalid#5234

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-3zsiiqs
Open

Fix phpstan/phpstan#14102: No error if construct signature of class-string of abstract class is invalid#5234
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-3zsiiqs

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When using class-string<AbstractClass> with new $className(), PHPStan was not checking constructor parameters if the class was abstract. This fix ensures constructor parameter validation works for abstract classes resolved from class-string types.

Changes

  • Modified src/Rules/Classes/InstantiationRule.php:
    • Removed !$classReflection->isAbstract() from the filter in getClassNames() so abstract classes from class-string types are included in constructor validation
    • Added $isFromClassString flag (third element in the return tuple) to distinguish class-string-resolved names from constant string or direct names
    • Skip class-string resolution when the type has constant strings (e.g. Foo::class), so those still correctly report "abstract class" errors via the existing path
    • Used $isFromClassString flag in checkClassName() to suppress the "Instantiated class X is abstract" error for class-string-resolved types
  • Updated tests/PHPStan/Rules/Classes/InstantiationRuleTest.php:
    • Added testBug14102() regression test
    • Updated testClassString() to expect constructor parameter errors for abstract class B
  • Added tests/PHPStan/Rules/Classes/data/bug-14102.php test data

Root cause

In InstantiationRule::getClassNames(), abstract classes were explicitly filtered out when resolving class-string types. This was overly conservative — while you can't directly instantiate an abstract class, class-string<AbstractClass> represents concrete subclasses that inherit the abstract class's constructor signature. The constructor parameters should still be validated.

The fix includes abstract classes in the class-string resolution but introduces a $isFromClassString flag to prevent false "Instantiated class X is abstract" errors. Constant string types (Foo::class) are excluded from the class-string path so they continue to correctly report abstract instantiation errors.

Test

Added tests/PHPStan/Rules/Classes/data/bug-14102.php which reproduces the exact scenario from the issue: an abstract class HelloWorld with a 2-parameter constructor, and a factory method accepting class-string<HelloWorld> that calls new $className() with 0 parameters. The test expects the error "Class Bug14102\HelloWorld constructor invoked with 0 parameters, 2 required."

Fixes phpstan/phpstan#14102

- Included abstract classes in class-string resolution in InstantiationRule::getClassNames()
- Added $isFromClassString flag to skip "abstract class" error for class-string-resolved types
- Constant string types (e.g. Foo::class) still go through the existing path and report abstract errors
- New regression test in tests/PHPStan/Rules/Classes/data/bug-14102.php
- Updated existing class-string test to expect errors for abstract class constructors
@ondrejmirtes
Copy link
Member

This is a new class of error that should only be there with bleeding edge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants