class-string and interface-string refinementsclass-string is phpdoc_advanced_fallback_class_string. This file
asks whether a type argument is applied (class-string<Contract>) and
whether interface-string is a distinct spelling.
References:
- PHPStan class-string and interface-string types
- Psalm class-string and interface-string types| Analyzer | Version | Result | Diagnostics |
|---|---|---|---|
| phan | 6.0.7Phan 6.0.7 php-ast version 1.1.3 PHP version used to run Phan: 8.5.9 | Unrecognized | phpdoc_advanced_generic_class_string.php:39: Saw possibly unextractable annotation for a fragment of comment '* @param interface-string<Contract> $interface': after interface, did not see an element name (will guess based on comment order) [PhanUnextractableAnnotationElementName] phpdoc_advanced_generic_class_string.php:39: Saw a token Phan may have failed to parse after '* @param interface-string<Contract> $interface': after interface, saw '-' [PhanUnextractableAnnotationSuffix] phpdoc_advanced_generic_class_string.php:41: Parameter $interface has undeclared type \Conformance\Tests\PhpdocAdvancedGenericClassString\interface [PhanUndeclaredTypeParameter] phpdoc_advanced_generic_class_string.php:47: Argument 1 ($interface) is Contract::class of type string but \Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractInterfaceString() takes \Conformance\Tests\PhpdocAdvancedGenericClassString\interface (no real type) defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_generic_class_string.php:41 (the inferred real argument type has nothing in common with the parameter's phpdoc type) [PhanTypeMismatchArgumentProbablyReal] phpdoc_advanced_generic_class_string.php:50: Argument 1 ($interface) is Implementation::class of type string but \Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractInterfaceString() takes \Conformance\Tests\PhpdocAdvancedGenericClassString\interface (no real type) defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_generic_class_string.php:41 (the inferred real argument type has nothing in common with the parameter's phpdoc type) [PhanTypeMismatchArgumentProbablyReal] phpdoc_advanced_generic_class_string.php:51: Possible use of a classlike '\not a class name' with an invalid FQSEN. [PhanInvalidFQSENInClasslike] phpdoc_advanced_generic_class_string.php:51: Argument 1 ($class) is 'not a class name' of type string but \Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString() takes class-string<\Conformance\Tests\PhpdocAdvancedGenericClassString\Contract> (no real type) defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_generic_class_string.php:34 (the inferred real argument type has nothing in common with the parameter's phpdoc type) [PhanTypeMismatchArgumentProbablyReal]
Expectation diffLine 47: Expected valid value to be accepted, got ["Argument 1 ($interface) is Contract::class of type string but \\Conformance\\Tests\\PhpdocAdvancedGenericClassString\\takesContractInterfaceString() takes \\Conformance\\Tests\\PhpdocAdvancedGenericClassString\\interface (no real type) defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_generic_class_string.php:41 (the inferred real argument type has nothing in common with the parameter's phpdoc type) [PhanTypeMismatchArgumentProbablyReal]"] |
| phpstan | 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 | Partly enforced (2/3) reported Lv.5+ | phpdoc_advanced_generic_class_string.php:49: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given. [reported-from-level=5] phpdoc_advanced_generic_class_string.php:51: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given. [reported-from-level=5] With strict-rulesphpdoc_advanced_generic_class_string.php:49: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given. phpdoc_advanced_generic_class_string.php:51: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given.
|
| psalm | 6.16.1Psalm 6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac next: 7.0.0-beta19 |
Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: Argument 1 of Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, but Conformance\Tests\PhpdocAdvancedGenericClassString\Unrelated::class provided [InvalidArgument] phpdoc_advanced_generic_class_string.php:51: Argument 1 of Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, but parent type 'not a class name' provided [ArgumentTypeCoercion] phpdoc_advanced_generic_class_string.php:51: Class, interface or enum named not a class name does not exist [UndefinedClass]
|
| mago | 1.47.4mago 1.47.4 | Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString`: expected `class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>`, but found `class-string('Conformance\Tests\PhpdocAdvancedGenericClassString\Unrelated')`. [invalid-argument]
phpdoc_advanced_generic_class_string.php:51: Possible argument type mismatch for argument #1 of `Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString`: expected `class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>`, but possibly received `string('not a class name')`. [possibly-invalid-argument]
|
| mir | 0.72.1mir 0.72.1 | Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: InvalidArgument: Argument $class of takesContractClassString() expects 'class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>', got 'class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Unrelated>' [MIR0201] phpdoc_advanced_generic_class_string.php:50: InvalidArgument: Argument $interface of takesContractInterfaceString() expects 'interface-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>', got 'class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Implementation>' [MIR0201]
|
| phpantom | 0.10.0phpantom_lsp 0.10.0 | Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: Argument 1 ($class) expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, got class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Unrelated> [type_mismatch_argument] phpdoc_advanced_generic_class_string.php:50: Argument 1 ($interface) expects interface-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, got class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Implementation> [type_mismatch_argument]
|
| intelephense | 1.18.5intelephense 1.18.5 | Not enforced | No diagnostics reported.
|
| phpactor | 2026.07.22.0Phpactor 2026.07.22.0 | Not enforced | No diagnostics reported.
|
| phpy | 0.2.0phpy 0.2.0 | Not enforced | No diagnostics reported.
|
| qodana | 262.9437.196Qodana 262.9437.196 | Unrecognized | phpdoc_advanced_generic_class_string.php:39: Undefined class 'interface-string' [PhpUndefinedClassInspection] phpdoc_advanced_generic_class_string.php:47: Parameter 'Contract::class' type is not compatible with declaration [PhpParamsInspection] phpdoc_advanced_generic_class_string.php:50: Parameter 'Implementation::class' type is not compatible with declaration [PhpParamsInspection]
Expectation diffLine 47: Expected valid value to be accepted, got ["Parameter 'Contract::class' type is not compatible with declaration [PhpParamsInspection]"] |
| noverify | 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 | Not enforced | No diagnostics reported.
|
| steins | 0.1.6steins 0.1.6 (2026-08-25 revision c13b4c7) | Not enforced | No diagnostics reported.
|
| phpstan-strict | 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 | Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given. phpdoc_advanced_generic_class_string.php:51: Parameter #1 $class of function Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, string given.
|
| psalm-next | 7.0.0-beta19Psalm 7.0.0-beta19@7e751c06a756fa64dc4c759c09fe4a173afcb433 | Partly enforced (2/3) | phpdoc_advanced_generic_class_string.php:49: Argument 1 of Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, but Conformance\Tests\PhpdocAdvancedGenericClassString\Unrelated::class provided [InvalidArgument] phpdoc_advanced_generic_class_string.php:51: Argument 1 of Conformance\Tests\PhpdocAdvancedGenericClassString\takesContractClassString expects class-string<Conformance\Tests\PhpdocAdvancedGenericClassString\Contract>, but parent type 'not a class name' provided [ArgumentTypeCoercion] phpdoc_advanced_generic_class_string.php:51: Class, interface or enum named not a class name does not exist [UndefinedClass]
|
<?php
declare(strict_types=1);
namespace Conformance\Tests\PhpdocAdvancedGenericClassString;
/**
* Generic `class-string` and `interface-string` refinements.
*
* Plain `class-string` is `phpdoc_advanced_fallback_class_string`. This file
* asks whether a type argument is applied (`class-string<Contract>`) and
* whether `interface-string` is a distinct spelling.
*
* References:
* - PHPStan class-string and interface-string types
* - Psalm class-string and interface-string types
*/
interface Contract
{
}
final class Implementation implements Contract
{
}
final class Unrelated
{
}
/**
* @param class-string<Contract> $class
*/
function takesContractClassString($class): void // T: class-string<Contract>
{
}
/**
* @param interface-string<Contract> $interface
*/
function takesContractInterfaceString($interface): void // T: interface-string<Contract>
{
}
takesContractClassString(Contract::class); // V
takesContractClassString(Implementation::class); // V
takesContractInterfaceString(Contract::class); // V
takesContractClassString(Unrelated::class); // E?: the class does not implement Contract
takesContractInterfaceString(Implementation::class); // E?: the name denotes a class, not an interface
takesContractClassString('not a class name'); // E?: a non-class string is not a class-string