callable(int): string case is callables_docblock_signature.
This file asks whether the extra parameter forms parse and then constrain
the callback that is passed.
References:
- PHPStan callable syntax
- Psalm callable 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 | Enforced | phpdoc_advanced_callable_signature_variants.php:67: Argument 1 ($callback) is (fn) of type Closure(string):string but \Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable() takes callable(int,int=):string defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_callable_signature_variants.php:22 (expected type to be the same or a subtype, but saw a supertype instead) [PhanTypeMismatchArgumentSuperType] phpdoc_advanced_callable_signature_variants.php:68: Argument 1 ($callback) is (fn) of type Closure(string):string but \Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesByReferenceCallable() takes callable(string $value&):mixed defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_callable_signature_variants.php:29 (expected type to be the same or a subtype, but saw a supertype instead) [PhanTypeMismatchArgumentSuperType] phpdoc_advanced_callable_signature_variants.php:69: Argument 1 ($callback) is (fn) of type Closure(float):int but \Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesVariadicCallable() takes callable(float $values...):(int|null) defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_callable_signature_variants.php:36 (expected type to be the same or a subtype, but saw a supertype instead) [PhanTypeMismatchArgumentSuperType] phpdoc_advanced_callable_signature_variants.php:70: Argument 1 ($callback) is (fn) of type Closure(string,string):string but \Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature() takes Closure(int,int):string defined at /Users/megurine/repo/php/php-typing-conformance/conformance/tests/phpdoc_advanced_callable_signature_variants.php:43 (expected type to be the same or a subtype, but saw a supertype instead) [PhanTypeMismatchArgumentSuperType]
|
| phpstan | 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 | Partly enforced (3/4) reported Lv.5+ | phpdoc_advanced_callable_signature_variants.php:67: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable expects callable(int, int=): string, Closure(string): string given. [reported-from-level=5] phpdoc_advanced_callable_signature_variants.php:69: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesVariadicCallable expects callable(float ...): (int|null), Closure(float): 1 given. [reported-from-level=5] phpdoc_advanced_callable_signature_variants.php:70: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature expects Closure(int, int): string, Closure(string, string): string given. [reported-from-level=5] With strict-rulesphpdoc_advanced_callable_signature_variants.php:67: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable expects callable(int, int=): string, Closure(string): string given. phpdoc_advanced_callable_signature_variants.php:69: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesVariadicCallable expects callable(float ...): (int|null), Closure(float): 1 given. phpdoc_advanced_callable_signature_variants.php:70: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature expects Closure(int, int): string, Closure(string, string): string given.
|
| psalm | 6.16.1Psalm 6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac next: 7.0.0-beta19 |
Unrecognized (pzoom≠) | phpdoc_advanced_callable_signature_variants.php:27: Invalid type '$value' in docblock for Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesByReferenceCallable [InvalidDocblock] phpdoc_advanced_callable_signature_variants.php:67: Argument 1 of Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable expects callable(int, int=):string, but pure-Closure(string):string provided [InvalidScalarArgument] phpdoc_advanced_callable_signature_variants.php:70: Argument 1 of Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature expects Closure(int, int):string, but pure-Closure(string, string):string provided [InvalidScalarArgument] pzoom (Psalm port)phpdoc_advanced_callable_signature_variants.php:67: Argument 1 of takesOptionalArgumentCallable expects callable(int, int=):string, but pure-Closure(string):string provided [PossiblyInvalidArgument] phpdoc_advanced_callable_signature_variants.php:70: Argument 1 of takesClosureSignature expects Closure(int, int):string, but pure-Closure(string, string):string provided [InvalidScalarArgument]
|
| mago | 1.47.4mago 1.47.4 | Partly enforced (2/4) | phpdoc_advanced_callable_signature_variants.php:67: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable`: expected `(callable(int, int=): string)`, but found `(closure(string): string)`. [invalid-argument] phpdoc_advanced_callable_signature_variants.php:70: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature`: expected `(closure(int, int): string)`, but found `(closure(string, string): string)`. [invalid-argument]
|
| mir | 0.72.1mir 0.72.1 | Incidental (4/4) | phpdoc_advanced_callable_signature_variants.php:57: InvalidArgument: Argument $callback of takesByReferenceCallable() expects 'callable whose parameter #1 accepts Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\string &', got 'callable whose parameter #1 only accepts string' [MIR0201] phpdoc_advanced_callable_signature_variants.php:67: InvalidArgument: Argument $callback of takesOptionalArgumentCallable() expects 'callable whose parameter #1 accepts int', got 'callable whose parameter #1 only accepts string' [MIR0201] phpdoc_advanced_callable_signature_variants.php:68: InvalidArgument: Argument $callback of takesByReferenceCallable() expects 'callable whose parameter #1 accepts Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\string &', got 'callable whose parameter #1 only accepts string' [MIR0201] phpdoc_advanced_callable_signature_variants.php:69: InvalidArgument: Argument $callback of takesVariadicCallable() expects 'callable whose parameter #1 accepts Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\float ...', got 'callable whose parameter #1 only accepts float' [MIR0201] phpdoc_advanced_callable_signature_variants.php:70: InvalidArgument: Argument $callback of takesClosureSignature() expects 'callable whose parameter #1 accepts int', got 'callable whose parameter #1 only accepts string' [MIR0201]
Expectation diffLine 57: Expected valid value to be accepted, got ["InvalidArgument: Argument $callback of takesByReferenceCallable() expects 'callable whose parameter #1 accepts Conformance\\Tests\\PhpdocAdvancedCallableSignatureVariants\\string &', got 'callable whose parameter #1 only accepts string' [MIR0201]"] |
| phpantom | 0.10.0phpantom_lsp 0.10.0 | Not enforced | No diagnostics reported.
|
| 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 | Not enforced | No diagnostics reported.
|
| noverify | 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 | Not enforced | phpdoc_advanced_callable_signature_variants.php:65: not null safety call in function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature signature of param callback [notNullSafetyFunctionArgumentVariable]
Expectation diffLine 65: Expected valid value to be accepted, got ["not null safety call in function Conformance\\Tests\\PhpdocAdvancedCallableSignatureVariants\\takesClosureSignature signature of param callback [notNullSafetyFunctionArgumentVariable]"] |
| steins | 0.1.6steins 0.1.6 (2026-08-25 revision c13b4c7) | Partly enforced (2/4) | phpdoc_advanced_callable_signature_variants.php:67: callable argument to takesOptionalArgumentCallable() violates declared @param callable(int, int=): string $callback — parameter #1 type is incompatible (callable parameter contravariance) [phpdoc.param-mismatch] phpdoc_advanced_callable_signature_variants.php:70: callable argument to takesClosureSignature() violates declared @param \Closure(int, int): string $callback — parameter #1 type is incompatible (callable parameter contravariance) [phpdoc.param-mismatch]
|
| phpstan-strict | 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 | Partly enforced (3/4) | phpdoc_advanced_callable_signature_variants.php:67: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable expects callable(int, int=): string, Closure(string): string given. phpdoc_advanced_callable_signature_variants.php:69: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesVariadicCallable expects callable(float ...): (int|null), Closure(float): 1 given. phpdoc_advanced_callable_signature_variants.php:70: Parameter #1 $callback of function Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature expects Closure(int, int): string, Closure(string, string): string given.
|
| psalm-next | 7.0.0-beta19Psalm 7.0.0-beta19@7e751c06a756fa64dc4c759c09fe4a173afcb433 | Unrecognized | phpdoc_advanced_callable_signature_variants.php:27: Invalid type '$value' in docblock for Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesByReferenceCallable [InvalidDocblock] phpdoc_advanced_callable_signature_variants.php:67: Argument 1 of Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesOptionalArgumentCallable expects impure-callable(int, int=):string, but pure-Closure(string):string provided [InvalidScalarArgument] phpdoc_advanced_callable_signature_variants.php:70: Argument 1 of Conformance\Tests\PhpdocAdvancedCallableSignatureVariants\takesClosureSignature expects impure-Closure(int, int):string, but pure-Closure(string, string):string provided [InvalidScalarArgument]
|
<?php
declare(strict_types=1);
namespace Conformance\Tests\PhpdocAdvancedCallableSignatureVariants;
/**
* Optional, by-reference, variadic, and Closure callable signatures.
*
* The baseline `callable(int): string` case is `callables_docblock_signature`.
* This file asks whether the extra parameter forms parse and then constrain
* the callback that is passed.
*
* References:
* - PHPStan callable syntax
* - Psalm callable types
*/
/**
* @param callable(int, int=): string $callback
*/
function takesOptionalArgumentCallable(callable $callback): void // T: callable(int, int=): string
{
}
/**
* @param callable(string &$value): mixed $callback
*/
function takesByReferenceCallable(callable $callback): void // T: callable(string &$value): mixed
{
}
/**
* @param callable(float ...$values): (int|null) $callback
*/
function takesVariadicCallable(callable $callback): void // T: callable(float ...$values): (int|null)
{
}
/**
* @param \Closure(int, int): string $callback
*/
function takesClosureSignature(\Closure $callback): void // T: \Closure(int, int): string
{
}
$optional = static function (int $first, int $second = 0): string {
return (string) ($first + $second);
};
takesOptionalArgumentCallable($optional); // V
$byReference = static function (string &$value): mixed {
$value = trim($value);
return $value;
};
takesByReferenceCallable($byReference); // V
$variadic = static function (float ...$values): int {
return count($values);
};
takesVariadicCallable($variadic); // V
$closure = static fn (int $first, int $second): string => (string) ($first + $second);
takesClosureSignature($closure); // V
takesOptionalArgumentCallable(static fn (string $value): string => $value); // E?: the required parameter is int, not string
takesByReferenceCallable(static fn (string $value): string => $value); // E?: the callback parameter must be passed by reference
takesVariadicCallable(static fn (float $value): int => 1); // E?: a fixed-arity callback is not variadic
takesClosureSignature(static fn (string $first, string $second): string => $first . $second); // E?: Closure parameters are int, not string