PHP 8.6: частичное применение функций без лишних замыканий
В PHP 8.6 появится Partial Function Application (PFA) — синтаксис, который позволяет зафиксировать часть аргументов вызова и получить готовое замыкание для оставшихся. Это небольшое изменение особенно заметно там, где сегодня приходится писать одноразовые стрелочные функции: в callbacks, преобразованиях коллекций и пайпах.
Что меняется по сравнению с first-class callables
Начиная с PHP 8.1 можно получить ссылку на функцию через запись с многоточием: trim(...). Она уже создаёт Closure, но передать в неё часть значений заранее нельзя. Если нужно заменить пробелы на дефисы, приходится вручную объявлять параметр и прокидывать его дальше.
$toSlug = fn (string $value): string => str_replace(' ', '-', $value);
$slugs = array_map($toSlug, $titles);
PFA оставляет в вызове плейсхолдер ?. Он означает: на этом месте аргумент появится позже. Результатом выражения становится Closure с корректной сигнатурой оставшихся параметров.
$toSlug = str_replace(' ', '-', ?);
$slugs = array_map($toSlug, $titles);
PFA — это не вызов «наполовину»
Функция в момент создания такой конструкции не выполняется. PHP создаёт обычное замыкание, которое вызовет исходную функцию, когда получит недостающие значения. По смыслу это тот же код, что и стрелочная функция, но без дублирования имён переменных, типов и порядка аргументов.
- ? резервирует ровно один аргумент; несколько знаков создают несколько параметров замыкания.
- ... оставляет незаполненными все остальные аргументы и соответствует first-class callable, если других значений нет.
- Плейсхолдеры можно сочетать с позиционными и именованными аргументами — это удобно, когда нужный параметр находится не последним.
- PFA работает с функциями, методами объектов, статическими и магическими методами; конструкторы исключены.
Callbacks становятся короче и понятнее
Хороший практический сценарий — адаптировать многопараметричную функцию под API, которое ждёт callback с одним аргументом. Например, заранее задать разрешённые статусы и включить строгое сравнение.
$allowed = ['new', 'paid', 'shipped'];
$isAllowed = in_array(?, $allowed, strict: true);
$visibleOrders = array_filter($orders, fn ($order) => $isAllowed($order->status));
В данном примере замыкание читается как правило предметной области: «проверить, входит ли переданное значение в разрешённый список». Не нужно искать тело callback, чтобы понять, что в нём зафиксировано.
Самое заметное сочетание — с pipe operator
Оператор |> из PHP 8.5 передаёт значение слева в callable справа. Когда функция принимает дополнительные параметры, раньше приходилось оборачивать её в стрелочную функцию. PFA превращает такую функцию в unary-callable прямо на месте, поэтому цепочка остаётся линейной.
$slug = $title
|> trim(...)
|> str_replace(' ', '-', ?)
|> str_replace(['.', '/', '…'], '', ?)
|> strtolower(...);
Это не повод превращать любой код в функциональную цепочку. Но для последовательных преобразований данных синтаксис уменьшает шум: хорошо видно и поток значения, и настройки каждой операции.
Именованные аргументы и отложенный запуск
Плейсхолдеры не обязаны стоять в конце. С именованными аргументами можно зафиксировать значения по смыслу, а порядок параметров будущего Closure будет определяться местами ?. Многоточие позволяет передать все оставшиеся параметры позднее — в том числе создать отложенный вызов без аргументов.
$makeBook = Book::make(
title: ?,
category: Category::TECH,
);
$saveReport = saveReport($report, ...);
if ($needsSaving) {
$saveReport();
}
На что обратить внимание перед использованием
PFA появится только в PHP 8.6, поэтому синтаксис нельзя применять в проектах на более ранней версии: парсер завершит работу до запуска приложения. До обновления PHP используйте привычные Closure и стрелочные функции.
- Проверьте минимальную версию PHP во всех окружениях: CI, очередях, CLI и production.
- Не используйте ... без необходимости в callback. Он передаёт лишние аргументы дальше, а у функций с необязательными параметрами это может изменить результат.
- Не рассчитывайте на PFA для new: частичное применение конструкторов специально не поддерживается.
- Оставляйте стрелочную функцию, если ей нужно не просто вызвать другую функцию, а добавить условие, преобразование или несколько действий.
Итог
Partial Function Application не меняет привычную модель PHP и не заменяет замыкания. Она убирает шаблонный код в одном конкретном случае — когда нужно зафиксировать часть аргументов уже существующего callable. В паре с pipe operator это сделает преобразования данных компактнее; в обычном прикладном коде — чуть точнее назовёт намерение.