array_map(fn ($x) => …, $listOfUsers) sees each $x as a
User, so a method User lacks is an error inside the callback.
The stubs for array_map and array_filter carry the callable signature
(callable(T): U, callable(T): bool); a tool that only reads the native
callable declaration leaves $x as mixed and stays silent.
References:
- PHPStan / Psalm array_map and array_filter stubs| Analyzer | Version | Result | Diagnostics |
|---|---|---|---|
| phan | 6.0.11Phan 6.0.11 php-ast version 1.1.3 PHP version used to run Phan: 8.5.11 | Pass | callables_closure_param_from_array_callback.php:34: Call to undeclared method \Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing [PhanUndeclaredMethod] callables_closure_param_from_array_callback.php:41: Call to undeclared method \Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing [PhanUndeclaredMethod] callables_closure_param_from_array_callback.php:48: Call to undeclared method \Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing [PhanUndeclaredMethod] |
| phpstan | 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 | Pass reported Lv.2+ | callables_closure_param_from_array_callback.php:34: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). [reported-from-level=2] callables_closure_param_from_array_callback.php:41: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). [reported-from-level=2] callables_closure_param_from_array_callback.php:48: Anonymous function should return string but returns mixed. [reported-from-level=10] callables_closure_param_from_array_callback.php:48: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). [reported-from-level=2] With strict-rulescallables_closure_param_from_array_callback.php:34: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). callables_closure_param_from_array_callback.php:41: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). callables_closure_param_from_array_callback.php:48: Anonymous function should return string but returns mixed. callables_closure_param_from_array_callback.php:48: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). |
| psalm | 6.20.9Psalm 6.20.9@f67170ac3c3b931f5088681e21d6c8babc601c08 next: 7.0.4 |
Pass (pzoom≠) | callables_closure_param_from_array_callback.php:34: Closure does not have a return type, expecting mixed [MissingClosureReturnType] callables_closure_param_from_array_callback.php:34: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:41: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:48: Could not infer a return type [MixedReturnStatement] callables_closure_param_from_array_callback.php:48: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] pzoom (Psalm port)callables_closure_param_from_array_callback.php:34: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:41: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:47: Could not infer a return type due to mixed return values [MixedReturnStatement] callables_closure_param_from_array_callback.php:48: Could not infer a return type [MixedReturnStatement] callables_closure_param_from_array_callback.php:48: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] |
| mago | 1.59.0mago 1.59.0 | Pass | callables_closure_param_from_array_callback.php:34: Method `missing` does not exist on type `Conformance\Tests\CallablesClosureParamFromArrayCallback\User`. [non-existent-method]
callables_closure_param_from_array_callback.php:41: Method `missing` does not exist on type `Conformance\Tests\CallablesClosureParamFromArrayCallback\User`. [non-existent-method]
callables_closure_param_from_array_callback.php:48: Method `missing` does not exist on type `Conformance\Tests\CallablesClosureParamFromArrayCallback\User`. [non-existent-method]
callables_closure_param_from_array_callback.php:48: Could not infer a precise return type for function `{closure:tests/callables_closure_param_from_array_callback.php:47:26}`. Saw type `mixed`. [mixed-return-statement] |
| mir | 0.91.0mir 0.91.0 | Pass | callables_closure_param_from_array_callback.php:34: UndefinedMethod: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() does not exist [MIR0004] callables_closure_param_from_array_callback.php:41: UndefinedMethod: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() does not exist [MIR0004] callables_closure_param_from_array_callback.php:48: UndefinedMethod: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() does not exist [MIR0004] callables_closure_param_from_array_callback.php:48: MixedReturnStatement: Cannot return a mixed type from function with declared return type 'string' [MIR1212] |
| phpantom | 0.11.1phpantom_lsp 0.11.1 | Pass | callables_closure_param_from_array_callback.php:34: Method 'missing' not found on class 'Conformance\Tests\CallablesClosureParamFromArrayCallback\User' [unknown_member] callables_closure_param_from_array_callback.php:41: Method 'missing' not found on class 'Conformance\Tests\CallablesClosureParamFromArrayCallback\User' [unknown_member] callables_closure_param_from_array_callback.php:48: Method 'missing' not found on class 'Conformance\Tests\CallablesClosureParamFromArrayCallback\User' [unknown_member] |
| intelephense | 1.18.5intelephense 1.18.5 | Pass | callables_closure_param_from_array_callback.php:34: Undefined method 'missing'. [P1013] callables_closure_param_from_array_callback.php:41: Undefined method 'missing'. [P1013] callables_closure_param_from_array_callback.php:48: Expected type 'string'. Found 'mixed'. [P1006] callables_closure_param_from_array_callback.php:48: Undefined method 'missing'. [P1013] |
| phpactor | 2026.10.07.0Phpactor 2026.10.07.0 | Fail | No diagnostics reported. Expectation diffLine 34: Expected 1 error(s) Line 41: Expected 1 error(s) Line 48: Expected 1 error(s) |
| phpy | 1.0.19490phpy 1.0.19490 | Pass | callables_closure_param_from_array_callback.php:34: Call to unknown method: Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() callables_closure_param_from_array_callback.php:41: Call to unknown method: Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() callables_closure_param_from_array_callback.php:48: Call to unknown method: Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing() |
| qodana | 262.11879.104PhpStorm 262.11879.104 | Fail | No diagnostics reported. Expectation diffLine 34: Expected 1 error(s) Line 41: Expected 1 error(s) Line 48: Expected 1 error(s) |
| noverify | 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 | Fail | callables_closure_param_from_array_callback.php:31: param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]
callables_closure_param_from_array_callback.php:38: param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]
callables_closure_param_from_array_callback.php:45: param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]
callables_closure_param_from_array_callback.php:48: Call to undefined method {\Conformance\Tests\CallablesClosureParamFromArrayCallback\User|mixed}->missing() [undefinedMethod]Expectation diffLine 34: Expected 1 error(s) Line 41: Expected 1 error(s) Line 31: Unexpected errors ["param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]"] Line 38: Unexpected errors ["param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]"] Line 45: Unexpected errors ["param $users miss matched with phpdoc type <<list<User>>> [funcParamTypeMissMatch]"] |
| steins | 0.1.8steins 0.1.8 (2026-09-21 revision 76306a9) | Fail | No diagnostics reported. Expectation diffLine 34: Expected 1 error(s) Line 41: Expected 1 error(s) Line 48: Expected 1 error(s) |
| phpstan-strict | 2.3.5PHPStan - PHP Static Analysis Tool 2.3.5 | Pass | callables_closure_param_from_array_callback.php:34: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). callables_closure_param_from_array_callback.php:41: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). callables_closure_param_from_array_callback.php:48: Anonymous function should return string but returns mixed. callables_closure_param_from_array_callback.php:48: Call to an undefined method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing(). |
| psalm-next | 7.0.4Psalm 7.0.4@fa5b1f6e665cb743838ffd865b8fc96207f9409f | Pass | callables_closure_param_from_array_callback.php:34: Closure does not have a return type, expecting mixed [MissingClosureReturnType] callables_closure_param_from_array_callback.php:34: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:41: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] callables_closure_param_from_array_callback.php:48: Could not infer a return type [MixedReturnStatement] callables_closure_param_from_array_callback.php:48: Method Conformance\Tests\CallablesClosureParamFromArrayCallback\User::missing does not exist [UndefinedMethod] |
<?php
declare(strict_types=1);
namespace Conformance\Tests\CallablesClosureParamFromArrayCallback;
/**
* Closure parameter types from array_map / array_filter.
*
* An untyped closure parameter takes its type from the array the callback is
* applied to: `array_map(fn ($x) => …, $listOfUsers)` sees each `$x` as a
* User, so a method User lacks is an error inside the callback.
*
* The stubs for `array_map` and `array_filter` carry the callable signature
* (`callable(T): U`, `callable(T): bool`); a tool that only reads the native
* `callable` declaration leaves `$x` as mixed and stays silent.
*
* References:
* - PHPStan / Psalm array_map and array_filter stubs
*/
final class User
{
public function name(): string
{
return 'user';
}
}
/** @param list<User> $users */
function mapsUsers(array $users): void
{
echo implode(',', array_map(fn ($user) => $user->name(), $users)); // V
echo count(array_map(fn ($user) => $user->missing(), $users)); // E: User has no missing()
}
/** @param list<User> $users */
function filtersUsers(array $users): void
{
echo count(array_filter($users, fn ($user) => $user->name() !== '')); // V
echo count(array_filter($users, fn ($user) => $user->missing() !== '')); // E: User has no missing()
}
/** @param list<User> $users */
function mapsUsersWithClosure(array $users): void
{
echo count(array_map(function ($user): string {
return $user->missing(); // E: User has no missing()
}, $users));
}