Partial function application means calling a function with only some of its arguments and getting back a closure that takes the rest later. Today you'd write an arrow function for that and copy every parameter and type by hand. This RFC from Larry Garfield and Arnaud Le Blanc adds a shorter syntax, where you put ? or ... in place of the missing arguments.
How it works
Before:
$result = array_map(static fn(string $string): string => str_replace('hello', 'hi', $string), $arr);
After:
$result = array_map(str_replace('hello', 'hi', ?), $arr);
There are two placeholders:
?stands for exactly one argument....stands for all the remaining arguments you didn't fill in.
function foo(int $a, int $b, int $c, int $d): int { return $a + $b + $c + $d; } $f = foo(1, ?, 3, 4); // same as: static fn(int $b): int => foo(1, $b, 3, 4); $f = foo(1, ...); // same as: static fn(int $b, int $c, int $d): int => foo(1, $b, $c, $d);
The closure you get back keeps the parameter names, types, defaults and return type of the original function, and reflection shows all of it. It also keeps the #[SensitiveParameter] and #[NoDiscard] attributes.
The RFC adds a few more rules:
- Named arguments work.
stuff(f: 3.14, s: 'two', ...)fills in two parameters by name and leaves the rest open. - Fill in everything plus
...and you get a closure with no parameters that runs the call later. - Arguments are evaluated right away. In
speak(?, getArg()),getArg()runs when you create the closure, not when you call it. That's different from an arrow function. - Methods, static methods, closures, invokable objects and
__call()all work, butnewdoesn't. Use a static factory method instead. - Constant expressions work too, like a property default, as long as every argument is constant.
- Some functions are off limits, like
compact(),extract()andfunc_get_arg(). These are the same ones first-class callables block.
This builds on the first-class callable syntax from PHP 8.1, since strlen(...) is really the simplest case of this feature. It also pairs well with the new pipe operator (|>).
What it means for existing code
Nothing breaks. The RFC only adds new syntax.
The vote
The RFC passed 33 to 0, clearing the two-thirds majority it needed, when voting closed on December 5, 2025. It was merged for PHP 8.6 and landed in 8.6 alpha3.