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.10Phan 6.0.10 php-ast version 1.1.3 PHP version used to run Phan: 8.5.11 | 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.3.1PHPStan - PHP Static Analysis Tool 2.3.1 | 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.20.0Psalm 6.20.0@804f03c0c183d149fcd4b8c7c0c9b3fbf836d34c next: 7.0.0-rc2 |
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.57.0mago 1.57.0 | 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.87.0mir 0.87.0 | 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.11.1phpantom_lsp 0.11.1 | 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.10.07.0Phpactor 2026.10.07.0 | Not enforced | No diagnostics reported.
|
| phpy | 1.0.19409phpy 1.0.19409 | Not enforced | No diagnostics reported.
|
| qodana | 262.10968.76PhpStorm 262.10968.76 | 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.8steins 0.1.8 (2026-09-21 revision 76306a9) | Not enforced | No diagnostics reported.
|
| phpstan-strict | 2.3.1PHPStan - PHP Static Analysis Tool 2.3.1 | 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-rc2Psalm 7.0.0-rc2@20339e3fe5b8d03bcd8061030eb2a83ad50e5783 | 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