PHP RFC: Partial Function Application (v2) =
- Version: 2.0
- Date: 2025-06-03
- Author: Larry Garfield (larry@garfieldtech.com), Arnaud Le Blanc (arnaud.lb@gmail.com)
- Status: Draft
- First Published at: https://wiki.php.net/rfc/partial_function_application_v2
Introduction
Partial Function Application (PFA) refers to the process of calling a function with only some of its required parameters, delaying the rest to a later time. It is logically equivalent to the following:
function f(int $a, int $b, int $c) {} $partialF = fn(int $b) => f(1, $b, 3);
However, using an arrow function is often cumbersome, as it requires manually replicating all the parameter information. That is unnecessary work both for the author and reader.
That is especially relevant when dealing with callbacks or the new pipe operator. For example:
$result = array_map(static fn(string $string): string => str_replace('hello', 'hi', $string), $arr); $foo |> static fn(array $arr) => array_map(static fn(string $string): string => str_replace('hello', 'hi', $string), $arr) ;
While the examples above show “all the trimmings,” including technically optional syntax, it is usually recommended to include type information, and many static analysis tools will require it. Even without the optional parts, there is still a lot of unnecessary and cumbersome indirection in the code.
With PFA as proposed here, the above examples could be simplified to:
$result = array_map(str_replace('hello', 'hi', ?), $arr); $foo |> array_map(str_replace('hello', 'hi', ?), ?) ;
That would produce the same result, but be vastly more ergonomic for all involved.
PFA is a core feature of a number of functional languages. While integrating it as a concept as deeply as, say, Haskell does is not feasible in PHP, the ergonomic benefits of PFA make it a key component of PHP's growing functional capabilities.
From one point of view, PFA is a natural extension of First-class callable syntax (FCC), added in PHP 8.1. Conversely, FCC is the degenerate case of PFA. The original FCC RFC was presented as a “first step” junior version of PFA, based on the syntax proposed by the Partial Function Application v1 RFC. FCC has clearly demonstrated its value in code simplification over the last few years, and PFA makes it even more powerful.
This RFC is substantially similar to the previous PFA RFC. It differs in a few design simplifications, and the implementation leverages the existing work of FCC.
Note that for the purposes of this RFC, “function” refers to any callable. Named function, named method, named static method, anonymous function, short-anonymous function, etc. Partial application applies to all of them.
Proposal
Overview
Partial Application consists of a function call in which one or more arguments is replaced with ?
or ...
. If that is found, then rather than calling the function the engine will create a Closure which stores the function and the arguments that were provided and return that. The Closure signature will be created to match the signature of the un-specified parameters. That means the closure can be inspected via reflection and will display the full type information for both parameters and the return value derived from the function.
For example, the following pairs are logically equivalent:
// Given function foo(int $a, $int $b, int $c, int $d): int { return $a + $b + $c + $d; } $f = foo(1, ?, 3, 4); $f = static fn(int $b): int => foo(1, $b, 3, 4); $f = foo(1, ?, 3, ?); $f = static fn(int $b, int $d): int => foo(1, $b, 3, $d); $f = foo(1, ...); $f = static fn(int $b, int $c, int $d): int => foo(1, $b, $c, $d); $f = foo(1, 2, ...); $f = static fn(int $c, int $d): int => foo(1, 2, $c, $d); $f = foo(1, ?, 3, ...); $f = static fn(int $b, int $d): int => foo(1, $b, 3, $d);
A partialed Closure may be partially applied again. In that case, the engine detects that it is a partial Closure and simply fills in additional arguments as appropriate, rather than creating another layer of wrapping Closure.
Placeholder Semantics
This RFC introduces two place holder symbols:
- The argument place holder
?
means that exactly one argument is expected at this position. - The variadic place holder
...
means that zero or more arguments may be supplied at this position.
The following rules apply to partial application:
...
may only occur zero or one time...
may only be followed by named arguments- named arguments must come after all place holders
- named placeholders are not supported
Backward Incompatible Changes
What breaks, and what is the justification for it?
Proposed PHP Version(s)
List the proposed PHP versions that the feature will be included in. Use relative versions such as “next PHP 8.x” or “next PHP 8.x.y”.
RFC Impact
To SAPIs
Describe the impact to CLI, Development web server, embedded PHP etc.
To Existing Extensions
Will existing extensions be affected?
To Opcache
It is necessary to develop RFC's with opcache in mind, since opcache is a core extension distributed with PHP.
Please explain how you have verified your RFC's compatibility with opcache.
New Constants
Describe any new constants so they can be accurately and comprehensively explained in the PHP documentation.
php.ini Defaults
If there are any php.ini settings then list:
- hardcoded default values
- php.ini-development values
- php.ini-production values
Open Issues
Make sure there are no open issues when the vote starts!
Unaffected PHP Functionality
List existing areas/features of PHP that will not be changed by the RFC.
This helps avoid any ambiguity, shows that you have thought deeply about the RFC's impact, and helps reduces mail list noise.
Future Scope
This section details areas where the feature might be improved in future, but that are not currently proposed in this RFC.
Proposed Voting Choices
Include these so readers know where you are heading and can discuss the proposed voting options.
Patches and Tests
Links to any external patches and tests go here.
If there is no patch, make it clear who will create a patch, or whether a volunteer to help with implementation is needed.
Make it clear if the patch is intended to be the final patch, or is just a prototype.
For changes affecting the core language, you should also provide a patch for the language specification.
Implementation
After the project is implemented, this section should contain
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
- a link to the language specification section (if any)
References
Links to external references, discussions or RFCs
Rejected Features
Keep this updated with features that were discussed on the mail lists.