Замыкания (closures) и first-class callables в константных выражениях PHP 8.5

Замыкания (closures) и first-class callables в константных выражениях PHP 8.5

Введение

PHP 8.5 принёс одну из самых долгожданных возможностей для атрибутов, дефолтных значений и констант — статические замыкания (closures) и first-class callables (...(...)) теперь разрешены в constant expressions.

Это не просто синтаксический сахар — это дверь в совершенно другой стиль написания конфигураций, валидаций, обработчиков событий и маппингов прямо в коде, без лишних классов и фабрик.

Что именно стало возможным

Место использования До PHP 8.5 PHP 8.5+ (новый синтаксис)
Дефолтное значение параметра ?Closure $cb = null + if внутри Closure $cb = static fn($v) => $v * 2
Дефолтное значение свойства Только скаляры / массивы / null private Closure $normalizer = static fn(string $s) => trim($s);
Параметр атрибута Строка, массив, константа, callable-массив #[Rule(callback: static fn($v) => $v > 0)]
Константа класса / глобальная Только immutable значения const PROCESSOR = self::normalizeData(...);
Массивы в атрибутах / константах Только простые значения const FILTERS = [static fn($v)=>filter_var($v,FILTER_VALIDATE_EMAIL), ...]

Самые важные правила и ограничения

  • Замыкание обязательно должно быть static function() {} или static fn() =>

В контексте константных выражений замыкание создаётся на этапе компиляции, когда ещё нет никакого $this. Поэтому PHP требует явного указания static, чтобы подчеркнуть: «это замыкание без привязки к объекту».

  • Запрещено захватывать переменные через use ($var)

Нет окружающего скоупа на этапе компиляции.

  • Нельзя использовать $this внутри

Замыкание создаётся на уровне компиляции, объекта ещё нет.

Разрешены:

  • статические методы классов через self::method(...)
  • глобальные функции через strlen(...)
  • first-class callables вида SomeClass::method(...)
  • стрелочные функции static fn($x) => $x * 2
  • обычные анонимные функции static function($x) { return $x * 2; }

Примеры использования

Замыкание как значение по умолчанию свойства

class User
{
    public ?Closure $normalizer =
        static fn (string $s) => trim(strtolower($s));
}

В атрибутах (очень мощно для валидаторов, прав доступа и т.д.)

#[Assert\Callback(
    callback: static fn ($value) => $value !== '' && strlen($value) >= 3
)]
class Product
{
    public string $name;
}

First-class callable (статические методы и обычные функции)

class Formatter
{
    public const NORMALIZE = 'strtolower(...)';          // работает
    public const TRIM_AND_LOWER = self::trimLower(...);  // тоже работает

    private static function trimLower(string $s): string
    {
        return trim(strtolower($s));
    }
}

В параметрах функций

function process(
    array $data,
    Closure $callback = static fn ($v) => $v * 2
): array {
    return array_map($callback, $data);
}

Массивы замыканий / callables в константах

const FILTERS = [
    'email'  => static fn ($v) => filter_var($v, FILTER_VALIDATE_EMAIL),
    'length' => 'strlen(...)',
    'slug'   => [self::class, 'makeSlug(...)'],
];

Похожие статьи

PHP 8.5: Обзор ключевых нововведений и улучшений

Это не просто очередной минорный апдейт: разработчики сосредоточились на том, что действительно важно современным PHP-программистам — чистый, выразительный и безопасный код.

Дублирование и клонирование записей с Laravel

Вам когда-нибудь приходилось дублировать или клонировать запись базы данных? Laravel предоставляет для этого очень удобную функцию.

Преобразовать HTML в PDF

Dompdf — конвертер HTML в PDF. По своей сути, dompdf — это (в основном) совместимый с CSS 2.1 HTML-макет и механизм рендеринга, написанный на PHP

Copyright © 2026 PHP Blog - шпаргалки программиста