← All results

Optional, by-reference, variadic, and Closure callable signatures

Group: Advanced PHPDoc types · Category: ecosystem · File: phpdoc_advanced_callable_signature_variants.php

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

Analyzer results

AnalyzerVersionResultDiagnostics
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]
  • Recognition: spelling resolved
  • Enforcement: 4/4 of the expected violations reported
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-rules
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.
  • Recognition: spelling resolved
  • Enforcement: 3/4 of the expected violations reported
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]
  • Recognition: spelling not resolved — reported on declaration line(s) 27
  • Enforcement: 2/4 of the expected violations reported — incidental, since the spelling was not resolved
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]
  • Recognition: spelling resolved
  • Enforcement: 2/4 of the expected violations reported
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]
  • Recognition: spelling resolved
  • Enforcement: 4/4 of the expected violations reported — incidental, since values the type admits were also rejected on line(s) 57
Expectation diff
Line 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.

  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations reported
intelephense 1.18.5intelephense 1.18.5 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations reported
phpactor 2026.07.22.0Phpactor 2026.07.22.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations reported
phpy 0.2.0phpy 0.2.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations reported
qodana 262.9437.196Qodana 262.9437.196 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations 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]
  • Recognition: spelling resolved
  • Enforcement: 0/4 of the expected violations reported
Expectation diff
Line 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]
  • Recognition: spelling resolved
  • Enforcement: 2/4 of the expected violations reported
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.
  • Recognition: spelling resolved
  • Enforcement: 3/4 of the expected violations reported
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]
  • Recognition: spelling not resolved — reported on declaration line(s) 27
  • Enforcement: 2/4 of the expected violations reported — incidental, since the spelling was not resolved

Source

<?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