Пишу, по большей части, про историю, свою жизнь и немного про программирование.

🐘 Кое-что новое об анонимных функциях PHP

Век живи, век учись. Даже чтение документации не избавляет от дыр в её знании, стоит пропустить одно-два предложения и не узнаешь о какой-то конструкции. Совершенно случайно заметил в документации любопытное сочетание ключевых слов. Внимание на пример ниже:

class Tester
{
    public function returnFunc()
    {
        return function() {
            return "Function call.\n";
        };
    }

    public function returnStaticFunc()
    {
        return static function() {
            return "Static function call.\n";
        };
    }

    public function __destruct()
    {
        echo "Tester died.\n";
    }
}

$holder = (new Tester)->returnFunc();
gc_collect_cycles();
echo $holder(); // «Function call.»
unset($holder);

$holderStatic = (new Tester)->returnStaticFunc();
gc_collect_cycles(); // дважды «Tester died»
echo $holderStatic(); // «Static function call.»

Обратите внимание на последовательность «return static». Дело в том, что анонимные функции в ПХП, если они создаются в методе, неявно захватывают его контекст, то есть переменную $this. В этом нет никакой беды, если функция короткоживующая.

В моём примере другая ситуация — объект возвращает анонимную функцию, но сам он уже не нужен. Логично было бы предположить, что его при следующей сборке прибъёт сборщик мусора (который я принудительно вызываю функцией gc_collect_cycles), но нет. Ссылка на него содержится в анонимной функции, порождённой методом returnFunc, ПХП интерпретатор и понятия не имеет нужен ли будет внутри контекст объекта, поэтому он его захватывает внутри на всякий случай.

Во втором подпримере конструкция «static function» говорит интерпретатору, что в ссылке на объект мы не нуждаемся, потому вызов gc_collect_cycles убивает два объекта — как предыдущего подпримера (так как переменная $holder уничтожена), так и из текущего, так как такая анонимная функция не содержит ссылку на объект.

2 комментария
SowingSadness 2016

Что-то не туда идут, мне кажется.
Раньше, если я не ошибаюсь, в PHP был синтаксис с with для лямбд и всё было хорошо.
И вместо действительного нужной функциональности, аля классы-друзья, делают что-то не нужное.

Евгений Степанищев (bolknote.ru) 2016

Комментарий для SowingSadness:

Что за синтаксис with для лямбд? Лямбд в PHP раньше не было. А когда они появились, появились они вместе со static.