PHP 8.6 introduces Partial Function Application (PFA). The feature is currently in beta, with a planned release around November 19, 2026.

PHP 8.1 introduced First-Class Callable Syntax, which turns an existing function into a callable with syntax such as `trim(...)`. This works with APIs such as `array_map()`. First-class callables do not bind selected arguments. PFA fills that gap by turning an expression such as `str_replace(' ', '-', ?)` into a callable that accepts the remaining value.

The `?` placeholder represents exactly one argument supplied later. Several placeholders are allowed, and they can appear among fixed positional or named arguments. PFA follows a fixed order: positional values and placeholders come first, named arguments follow, and at most one trailing `...` can appear at the end. The ellipsis leaves all remaining argument slots open.

PFA is designed for callback-heavy code. An `array_map()` call can pass `str_replace('hello', 'hi', ?)` directly as its callback. With `array_filter()`, `mode: ?` can remain open while `is_numeric(...)` fixes the callback and a trailing `...` leaves the array argument for the later call. The resulting callable accepts either positional values such as `0` and `[1, 'a', 2, 'b', 3]`, or named arguments such as `mode: 0` and `array: [1, 'a', 2, 'b', 3]`.

The ellipsis also supports deferred execution. A callable created from `printf('Hello, %s!' . PHP_EOL, ...)` can be invoked later when the greeting is needed. PFA works with the pipe operator, where `str_replace(' ', '-', ?)` receives the value passed through the pipeline. Static and instance methods support the same mechanism. The examples use `Book::create(category: Category::THRILLER, title: ?)` and `$book->publish(new DateTimeImmutable(), ...)`.

Fixed arguments are evaluated when the partial callable is created. In the example with `getPrefix()`, the function prints `Called!`, returns `PHP`, and runs during creation. The returned value is captured for later calls such as `$partial('Alice')` and `$partial('Bob')`. A regular closure evaluates an expression such as `getPrefix()` when each invocation runs.

PFA creates a new closure. It does not preserve all metadata from the original callable. Custom attributes such as `#[MyAttribute]` are dropped, while `#[NoDiscard]` and `#[SensitiveParameter]` are exceptions. `#[SensitiveParameter]` remains available when its parameter stays open. Reflection code must account for these differences. The article also notes that some special constructs are unsupported, without listing them.