Підтримка анонімних функцій у константних виразах у PHP 8.5

Перекладено ШІ
Оригінал: Laravel News
Оновлено: 21 жовтня, 2025
PHP 8.5 приносить захоплюючі зміни, зокрема можливість використовувати замикання у константних виразах, що відкриває нові можливості для розробників. Які переваги це надає при написанні коду? Дізнайтеся більше в нашій статті!

PHP 8.5 вводить підтримку closures у константних виразах, що дозволяє визначати значення за замовчуванням атрибутів як Closure та відкриває нові можливості. У RFC детально пояснюється, що це означає для мови PHP:

Декілька конструкцій PHP обмежені лише "константними виразами". Ці вирази можуть містити лише обмежену кількість операцій, що можна охарактеризувати як "незмінні значення". Наприклад, параметри атрибутів можуть приймати лише константні вирази, але Closure не були частиною дозволених операцій.

Оскільки Closure фактично є кодом PHP (або PHP Opcodes), вони вважаються незмінними значеннями (за умови обмеження деяких функцій), і немає жодної принципової причини, чому їх не можна використовувати в константних виразах. І дійсно, є кілька випадків, коли їх використання в константних виразах стане в нагоді.

Розглянемо приклад нововведень для аргументів функцій і методів PHP. Тепер ви можете визначити значення за замовчуванням прямо в аргументах, не вимагаючи, щоб екземпляр Closure був null:

function my_array_filter(
    array $array,
    Closure $callback = static function ($item) { return !empty($item); },
) {
    $result = [];
 
    foreach ($array as $item) {
        if ($callback($item)) {
            $result[] = $item;
        }
    }
 
    return $result;
}
 
my_array_filter([
    0, 1, 2,
    '', 'foo', 'bar',
]); // [1, 2, "foo", "bar"]

Раніше, до виходу PHP 8.5, вам потрібно було визначити closure як null за замовчуванням і призначити значення Closure, якщо користувач не надавав його:

function my_array_filter(array $array, ?Closure $callback = null)
{
    $callback ??= static fn ($item) => !empty($item);
    $result = [];
 
    foreach ($array as $item) {
        if ($callback($item)) {
            $result[] = $item;
        }
    }
 
    return $result;
}

Хоча визначити за замовчуванням у функції не так вже й незручно, існує безліч прикладів, що відкривають нові можливості для атрибутів PHP та інших випадків:

// Closures в атрибутах PHP
final class Locale
{
    #[Validator\Custom(static function (string $languageCode): bool {
        return \preg_match('/^[a-z][a-z]$/', $languageCode);
    })]
    public string $languageCode;
}
 
// Closures у підвиразах
function foo(
    string $input,
    array $callbacks = [
        static function ($value) {
            return \strtoupper($value);
        },
        static function ($value) {
            return \preg_replace('/[^A-Z]/', '', $value);
        },
    ]
) {
    foreach ($callbacks as $callback) {
        $input = $callback($input);
    }
 
    return $input;
}
 
foo('Hello, World!'); // string(10) "HELLOWORLD"

# Дізнайтеся більше

Код для RFC пропозиції вже реалізовано та об'єднано в основну гілку виходу PHP на момент написання.

Щоб дізнатися більше, ознайомтесь з RFC пропозицією для детальнішої інформації rfc:closures_in_const_expr та перегляньте наш пост про все нове у PHP 8.5.