You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
infer closure type from being passed into function's return type with callable signature #11317
I have a closure that passes a closure-parameter to an external method.
<?phpclass A {
/** * @param array{string, int, bool} $array */publicfunctiondo(array$array): B
{
returnnewB;
}
}
class B {}
class C {
publicfunction__construct(privateA$a) {}
/** * @return Callable(array{string, int, bool}): B */publicfunctiongetCallable(): Callable
{
/** * @param array{string, int, bool} */returnfunction (array$array): B
{
return$this->a->do($array);
};
}
}
The closure return type has been declared with the correct parameter-type and inside the function the parameteres of the returned closure are also declared correctly.
Yet PHPStan complaints that the function called within the closure "expects array{string, int, bool}, array given".
I am sure I am missing something somewhere as I doubt that I am the only one stumbling over this.
I figured I could "fix" this by adding a /** @var array{string, int, bool} $array */ right before passing the variable inside the closure. But that seems to be a hacky patch for something that should be solved differently as all the information should already be available.
And there's a feature request for this already: #3770
The reason why we didn't add this yet is because PHPStan is pretty smart about inferring closure parameter and return type automatically based on where the closure is passed to. Some examples:
Recently added *ClosureTypeExtensions that allow Larastan to infer precise closure type with custom logic:
User::doesntHave('accounts', 'and', function (Builder$query) {
// Builder<Account> because it figures that out based on `User` and `accounts`\PHPStan\dumpType($query);
});
So in my experience this is much better than requiring the user to write @param and @return above their closures.
I'm typing this all out because I have a similar suggestion here. When looking at the code sample, PHPStan could figure out what's going to be passed into the closure based on the @returnabove the method thanks to the fact the closure is directly in return statement:
Adding the PHPDoc above the closure was merely a try to see whether it fixes the issue. I would be totally happy for PHPStan to infer the type from the @return annotation of the function returning the callable as you have sketched out above!
But I did get you right that that is an idea how to solve that and not yet working code, didn't I? 'Cause currently the PHPSTan\dumpType() merely prints array...
changed the title [-]Can't declare parameter expectations within closures[/-][+]infer closure type from being passed into function's return type with callable signature[/+]on Jul 11, 2024
Activity
heiglandreas commentedon Jul 10, 2024
I figured I could "fix" this by adding a
/** @var array{string, int, bool} $array */right before passing the variable inside the closure. But that seems to be a hacky patch for something that should be solved differently as all the information should already be available.See https://phpstan.org/r/c6ef9c9b-8444-4b45-a3de-5493de78738a
ondrejmirtes commentedon Jul 10, 2024
Hello Andreas,
PHPStan currently doesn't read PHPDocs above closures so this PHPDoc is not used at all:
And there's a feature request for this already: #3770
The reason why we didn't add this yet is because PHPStan is pretty smart about inferring closure parameter and return type automatically based on where the closure is passed to. Some examples:
array_mapandarray_filterwill correctly get the parameter type based on the array passed into the function call: https://phpstan.org/r/c3921b14-1546-4848-8058-07d149e98f4a*ClosureTypeExtensionsthat allow Larastan to infer precise closure type with custom logic:So in my experience this is much better than requiring the user to write
@paramand@returnabove their closures.I'm typing this all out because I have a similar suggestion here. When looking at the code sample, PHPStan could figure out what's going to be passed into the closure based on the
@returnabove the method thanks to the fact the closure is directly inreturnstatement:WDYT?
heiglandreas commentedon Jul 11, 2024
Hey @ondrejmirtes.
Adding the PHPDoc above the closure was merely a try to see whether it fixes the issue. I would be totally happy for PHPStan to infer the type from the
@returnannotation of the function returning the callable as you have sketched out above!But I did get you right that that is an idea how to solve that and not yet working code, didn't I? 'Cause currently the
PHPSTan\dumpType()merely printsarray...ondrejmirtes commentedon Jul 11, 2024
Yes, it's just a suggestion how PHPStan could be improved 😊
[-]Can't declare parameter expectations within closures[/-][+]infer closure type from being passed into function's return type with callable signature[/+]phpstan-bot commentedon Sep 4, 2024
@heiglandreas After the latest push in 2.0.x, PHPStan now reports different result with your code snippet:
Full report
PHP 8.0 – 8.3 (2 errors)
PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.PHP 7.2 – 7.4 (3 errors)
Promoted properties are supported only on PHP 8.0 and later.PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.phpstan-bot commentedon Sep 7, 2024
@heiglandreas After the latest push in 2.0.x, PHPStan now reports different result with your code snippet:
Full report
PHP 8.0 – 8.3 (2 errors)
PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.PHP 7.2 – 7.4 (3 errors)
Promoted properties are supported only on PHP 8.0 and later.PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.phpstan-bot commentedon Sep 8, 2024
@heiglandreas After the latest push in 2.0.x, PHPStan now reports different result with your code snippet:
Full report
PHP 8.0 – 8.3 (2 errors)
PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40 on line 2Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.PHP 7.2 – 7.4 (3 errors)
Promoted properties are supported only on PHP 8.0 and later.PHPDoc tag @param has invalid value (array{string, int, bool}): Unexpected token "\n\t\t ", expected variable at offset 40 on line 2Parameter #1 $array of method A::do() expects array{string, int, bool}, array given.ondrejmirtes commentedon Nov 3, 2024
It's very easy to implement. We need to update this place: https://github.com/phpstan/phpstan-src/blob/88d5b8cf0cb2da8873dc33222b5f8b4727f0756a/src/Analyser/NodeScopeResolver.php#L757-L761
And call
processClosureNode/processArrowFunctionNodewith the method's return type as$passedToType.Add regression test for #11317
phpstan-bot commentedon Jul 7, 2026
@ondrejmirtes After the latest push in 2.2.x, PHPStan now reports different result with your code snippet:
Full report
Call to function array_map() on a separate line has no effect.Dumped type: intAdd regression test for #11317
Add regression test for #11317
Updated PHPStan to commit c871d1f9a556bb764f0a4527032ceeebe17437de
github-actions commentedon Oct 29, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.