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.10Phan 6.0.10 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.1PHPStan - PHP Static Analysis Tool 2.3.1 | 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.0Psalm 6.20.0@804f03c0c183d149fcd4b8c7c0c9b3fbf836d34c next: 7.0.0-rc2 |
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] |
| mago | 1.57.0mago 1.57.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.87.0mir 0.87.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.19409phpy 1.0.19409 | Fail | No diagnostics reported. Expectation diffLine 34: Expected 1 error(s) Line 41: Expected 1 error(s) Line 48: Expected 1 error(s) |
| qodana | 262.10968.76PhpStorm 262.10968.76 | 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.1PHPStan - PHP Static Analysis Tool 2.3.1 | 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.0-rc2Psalm 7.0.0-rc2@20339e3fe5b8d03bcd8061030eb2a83ad50e5783 | 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));
}