callable-array[$object, 'method'] form PHP accepts as a callable. It asks
more of an analyzer than the other callable refinements: recognising it means
checking the shape of the array *and* resolving the method name against the
first element's class. Analyzers that model it reject an array that is merely
a pair of values; others fall back to plain array and accept it.
References:
- PHPStan TypeNodeResolver callable-array resolves to array&CallableType| 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 | Not enforced | No diagnostics reported.
|
| phpstan | 2.2.8PHPStan - PHP Static Analysis Tool 2.2.8 | Enforced reported Lv.5+ | phpdoc_advanced_fallback_callable_array.php:56: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, 'missing'} given. [identifier=argument.type] [reported-from-level=5]
phpdoc_advanced_fallback_callable_array.php:59: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{1, 2} given. [identifier=argument.type] [reported-from-level=7]With strict-rulesphpdoc_advanced_fallback_callable_array.php:56: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, 'missing'} given. [identifier=argument.type]
phpdoc_advanced_fallback_callable_array.php:59: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{1, 2} given. [identifier=argument.type]
Notes: Tracked upstream. See phpstan#13114 |
| psalm | 6.16.1Psalm 6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac next: 7.0.0-beta19 |
Partly enforced (1/2) | phpdoc_advanced_fallback_callable_array.php:59: Argument 1 of Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects list{class-string|object, non-empty-string}, but list{1, 2} provided [InvalidArgument]
|
| mago | 1.46.0mago 1.46.0 | Unrecognized | phpdoc_advanced_fallback_callable_array.php:28: Cannot find class, interface, enum, or type alias `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array`. [non-existent-class-like]
phpdoc_advanced_fallback_callable_array.php:32: Invalid return type for function `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\returnsCallableArray`: expected `unknown-ref(Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array)`, but found `list{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, string('greet')}`. [invalid-return-statement]
phpdoc_advanced_fallback_callable_array.php:43: Cannot find class, interface, enum, or type alias `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array`. [non-existent-class-like]
phpdoc_advanced_fallback_callable_array.php:50: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsArray`: expected `array<array-key, mixed>`, but found `unknown-ref(Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array)`. [invalid-argument]
phpdoc_advanced_fallback_callable_array.php:53: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray`: expected `unknown-ref(Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array)`, but found `list{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, string('greet')}`. [invalid-argument]
phpdoc_advanced_fallback_callable_array.php:56: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray`: expected `unknown-ref(Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array)`, but found `list{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, string('missing')}`. [invalid-argument]
phpdoc_advanced_fallback_callable_array.php:59: Invalid argument type for argument #1 of `Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray`: expected `unknown-ref(Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array)`, but found `list{int(1), int(2)}`. [invalid-argument]
Expectation diffLine 32: Expected valid value to be accepted, got ["Invalid return type for function `Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\returnsCallableArray`: expected `unknown-ref(Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array)`, but found `list{Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\Greeter, string('greet')}`. [invalid-return-statement]"]
Line 50: Expected valid value to be accepted, got ["Invalid argument type for argument #1 of `Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\acceptsArray`: expected `array<array-key, mixed>`, but found `unknown-ref(Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array)`. [invalid-argument]"]
Line 53: Expected valid value to be accepted, got ["Invalid argument type for argument #1 of `Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\acceptsCallableArray`: expected `unknown-ref(Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array)`, but found `list{Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\Greeter, string('greet')}`. [invalid-argument]"] |
| mir | 0.70.1mir 0.70.1 | Incidental (2/2) | phpdoc_advanced_fallback_callable_array.php:50: InvalidArgument: Argument $value of acceptsArray() expects 'array', got 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array' [MIR0201]
phpdoc_advanced_fallback_callable_array.php:53: InvalidArgument: Argument $value of acceptsCallableArray() expects 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array', got 'array{0: Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, 1: "greet"}' [MIR0201]
phpdoc_advanced_fallback_callable_array.php:56: InvalidArgument: Argument $value of acceptsCallableArray() expects 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array', got 'array{0: Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, 1: "missing"}' [MIR0201]
phpdoc_advanced_fallback_callable_array.php:59: InvalidArgument: Argument $value of acceptsCallableArray() expects 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array', got 'array{0: 1, 1: 2}' [MIR0201]
Expectation diffLine 50: Expected valid value to be accepted, got ["InvalidArgument: Argument $value of acceptsArray() expects 'array', got 'Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array' [MIR0201]"]
Line 53: Expected valid value to be accepted, got ["InvalidArgument: Argument $value of acceptsCallableArray() expects 'Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array', got 'array{0: Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\Greeter, 1: \"greet\"}' [MIR0201]"] |
| phpantom | 0.9.0phpantom_lsp 0.9.0 | Not enforced | No diagnostics reported.
|
| intelephense | 1.18.5intelephense 1.18.5 | Not enforced | No diagnostics reported.
|
| phpy | 0.2.0phpy 0.2.0 | Unrecognized | phpdoc_advanced_fallback_callable_array.php:28: Use of unknown class: 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array' phpdoc_advanced_fallback_callable_array.php:32: Return value of Conformance\Tests\PhpdocAdvancedFallbackCallableArray\returnsCallableArray() is expected to be of type Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array, array returned phpdoc_advanced_fallback_callable_array.php:43: Use of unknown class: 'Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array' phpdoc_advanced_fallback_callable_array.php:50: Argument '1' passed to Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsArray() is expected to be of type array, Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array given phpdoc_advanced_fallback_callable_array.php:53: Argument '1' passed to Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray() is expected to be of type Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array, array given phpdoc_advanced_fallback_callable_array.php:56: Argument '1' passed to Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray() is expected to be of type Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array, array given phpdoc_advanced_fallback_callable_array.php:59: Argument '1' passed to Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray() is expected to be of type Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array, array given
Expectation diffLine 32: Expected valid value to be accepted, got ["Return value of Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\returnsCallableArray() is expected to be of type Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array, array returned"] Line 50: Expected valid value to be accepted, got ["Argument '1' passed to Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\acceptsArray() is expected to be of type array, Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array given"] Line 53: Expected valid value to be accepted, got ["Argument '1' passed to Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\acceptsCallableArray() is expected to be of type Conformance\\Tests\\PhpdocAdvancedFallbackCallableArray\\callable-array, array given"] |
| qodana | 262.8665.325Qodana 262.8665.325 | Unrecognized | phpdoc_advanced_fallback_callable_array.php:28: Return type in PHPDoc does not match the actual return type [PhpReturnDocTypeMismatchInspection] phpdoc_advanced_fallback_callable_array.php:28: Undefined class 'callable-array' [PhpUndefinedClassInspection] phpdoc_advanced_fallback_callable_array.php:32: Return value type is not compatible with declared [PhpIncompatibleReturnTypeInspection] phpdoc_advanced_fallback_callable_array.php:43: Undefined class 'callable-array' [PhpUndefinedClassInspection] phpdoc_advanced_fallback_callable_array.php:53: Parameter '[new Greeter(), 'greet']' type is not compatible with declaration [PhpParamsInspection] phpdoc_advanced_fallback_callable_array.php:56: Parameter '[new Greeter(), 'missing']' type is not compatible with declaration [PhpParamsInspection] phpdoc_advanced_fallback_callable_array.php:59: Parameter '[1, 2]' type is not compatible with declaration [PhpParamsInspection]
Expectation diffLine 32: Expected valid value to be accepted, got ["Return value type is not compatible with declared [PhpIncompatibleReturnTypeInspection]"] Line 53: Expected valid value to be accepted, got ["Parameter '[new Greeter(), 'greet']' 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 | Unrecognized ⚠ 1 false positive | phpdoc_advanced_fallback_callable_array.php:28: Class or interface named \Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array does not exist [undefinedClass] phpdoc_advanced_fallback_callable_array.php:38: param $value miss matched with phpdoc type <<array<mixed>>> [funcParamTypeMissMatch] phpdoc_advanced_fallback_callable_array.php:43: Class or interface named \Conformance\Tests\PhpdocAdvancedFallbackCallableArray\callable-array does not exist [undefinedClass]
Expectation diffLine 38: Unexpected errors ["param $value miss matched with phpdoc type <<array<mixed>>> [funcParamTypeMissMatch]"] |
| steins | 0.1.5steins 0.1.5 (2026-08-12 revision 39b4cc1) | Not enforced | No diagnostics reported.
|
| phpstan-strict | 2.2.8PHPStan - PHP Static Analysis Tool 2.2.8 | Enforced | phpdoc_advanced_fallback_callable_array.php:56: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{Conformance\Tests\PhpdocAdvancedFallbackCallableArray\Greeter, 'missing'} given. [identifier=argument.type]
phpdoc_advanced_fallback_callable_array.php:59: Parameter #1 $value of function Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects non-empty-list&callable(): mixed, array{1, 2} given. [identifier=argument.type]
Notes: Tracked upstream. See phpstan#13114 |
| psalm-next | 7.0.0-beta19Psalm 7.0.0-beta19@7e751c06a756fa64dc4c759c09fe4a173afcb433 | Partly enforced (1/2) | phpdoc_advanced_fallback_callable_array.php:59: Argument 1 of Conformance\Tests\PhpdocAdvancedFallbackCallableArray\acceptsCallableArray expects array{0: class-string|object, 1: non-empty-string}, but list{1, 2} provided [InvalidArgument]
|
<?php
declare(strict_types=1);
namespace Conformance\Tests\PhpdocAdvancedFallbackCallableArray;
/**
* `callable-array`
*
* The two-element `[$object, 'method']` form PHP accepts as a callable. It asks
* more of an analyzer than the other callable refinements: recognising it means
* checking the shape of the array *and* resolving the method name against the
* first element's class. Analyzers that model it reject an array that is merely
* a pair of values; others fall back to plain `array` and accept it.
*
* References:
* - PHPStan TypeNodeResolver `callable-array` resolves to array&CallableType
*/
final class Greeter
{
public function greet(): void
{
}
}
/**
* @return callable-array
*/
function returnsCallableArray() // T: callable-array
{
return [new Greeter(), 'greet']; // V
}
/**
* @param array<mixed> $value
*/
function acceptsArray(array $value): void
{
}
/**
* @param callable-array $value
*/
function acceptsCallableArray($value): void // T: callable-array
{
}
// A `callable-array` value always satisfies a native `array` parameter.
acceptsArray(returnsCallableArray()); // V
// The object/method pair satisfies the parameter.
acceptsCallableArray([new Greeter(), 'greet']); // V
// A pair naming a method that does not exist does not.
acceptsCallableArray([new Greeter(), 'missing']); // E?: the method does not exist, so this is not a callable-array
// Nor does an array that is simply two values.
acceptsCallableArray([1, 2]); // E?: [1, 2] is not a callable-array