Чем статическое замыкание (static closure) отличается от обычного в PHP?

«Чем статическое замыкание (static closure) отличается от обычного в PHP?» — вопрос из категории PHP Core, который задают на 24% собеседований PHP Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основное отличие — статическое замыкание не имеет доступа к псевдопеременной $this и не захватывает контекст объекта, в котором оно было объявлено. Ключевое слово static перед function накладывает это ограничение.

Обычное замыкание автоматически захватывает $this, если объявлено в контексте метода объекта:

class Logger {
    private string $prefix = 'LOG:';

    public function getClosure(): Closure {
        // Обычное замыкание ЗАХВАТЫВАЕТ $this
        return function ($message) {
            // Имеет доступ к private-свойству $this->prefix
            echo $this->prefix . ' ' . $message;
        };
    }
}

$logger = new Logger();
$closure = $logger->getClosure();
$closure('Test'); // Вывод: LOG: Test

Статическое замыкание не может использовать $this, даже если создано внутри метода:

class Logger {
    private string $prefix = 'LOG:';

    public function getStaticClosure(): Closure {
        $prefix = $this->prefix; // Нужно явно захватить значение
        // Статическое замыкание НЕ ЗАХВАТЫВАЕТ $this
        return static function ($message) use ($prefix) {
            // echo $this->prefix; // ФАТАЛЬНАЯ ОШИБКА: Using $this when not in object context
            echo $prefix . ' ' . $message; // Работает, т.к. $prefix захвачена явно
        };
    }
}

Зачем это нужно?

  1. Явное указание намерений: Код показывает, что замыкание не зависит от состояния объекта.
  2. Предотвращение утечек памяти: Поскольку нет ссылки на порождающий объект ($this), этот объект может быть удалён сборщиком мусора, даже если замыкание ещё существует. В обычном замыкании объект будет жить, пока живо замыкание.
  3. Использование в статическом контексте: Статические замыкания можно безопасно использовать в статических методах или там, где контекст объекта не определён.
  4. Оптимизация: Небольшой выигрыш в производительности, так как не требуется обработка контекста объекта.

Вывод: Используйте static closure, когда ваша анонимная функция является чистой (не зависит от состояния объекта) или должна пережить объект, в котором создана.