Этот сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Анонимные функции в PHP

Относительно недавно в ПХП появился новый способ создания анонимных функций. Раньше мы писали array_filter($strs, 'strlen'), теперь можем писать array_filter($strs, strlen(...)).

В первом случае у нас указывается строка, во втором — анонимная функция. Последнее намного лучше, конечно, потому что помогает строгой типизации и лучше понимается редакторами кода.

Когда этот синтаксис появился, в моей голове он стал частным случаем стрелочного синтаксиса. В самом деле, ведь fn($t) => sin($t) и sin(...) — это одно и то же. Но недавно я понял, что у второго синтаксиса есть побочный эффект. По какой-то причине раньше мне это было не очевидно.

Если посмотреть на код ниже, всё должно стать понятно, но если нет, то я поясню.

Тут мы видим класс, конструктор которого печатает код, находящийся в строке, которая его вызвала. Ниже класса создаются две анонимные функции, одна — стрелочная через fn(), вторая — через многоточие.

Этот код позволяет проиллюстрировать разницу.

В случае создания анонимной функции через fn(), конструктор будет вызван каждый раз заново на любой вызов функции.

В случае синтаксиса с многоточием, конструктор будет вызван сразу при создании, а при вызове, в том числе многократном, он вызываться не будет.

То есть каждый способ имеет особенности, которые надо учитывать.

class Sample
{
    public function __construct()
    {
        $bt = debug_backtrace();
        ['line' => $line, 'file' => $filename] = end($bt);

        echo file($filename)[$line - 1];
    }

    public function method(): void
    {
    }
}

$a = fn() => (new Sample)->method(); // не выведет ничего
$b = (new Sample)->method(...); // выведется «$b = (new Sample)->method(...);»

$a(); $a(); // выведется «$a(); $a();» два раза
$b(); $b(); // не выведет ничего
1 комментарий
hsh 6 дн

В самом деле, ведь fn($t) => sin($t) и sin(...)

static fn ($v) => sin($v)

Евгений Степанищев 5 дн

Да, ваша правда, но в данном случае мне показалось, что это лишняя подробность.