Замыкания и анонимные функции в PHP

Замыкания и анонимные функции появились в PHP 5.3.0. Замыкание - это функция, которая инкапсулирует состояние окружавшее ее на момент создания. Инкапсулированное состояние продолжает существовать внутри замыкания, даже когда окружение замыкания перестает существовать. Не пугайтесь, приведенное определение данного термина является академическим и далее будет все намного понятнее.

Если вы хотите ознакомиться с материалом в видео формате, вы можете найти запись в лектории или просто перейти по ссылке. Также вы сможете получить методичку и перезентацию на данную тему под видео - лекцией.

Анонимные функции - это всего лишь функции без имени. Анонимные функции могут присваиваться в качестве значений переменным.

Теоретически замыкания и анонимные функции - это абсолютно разные понятия, но в мире PHP они равнозначны, то есть являются одним и тем же. Если мы говорим о замыкании, то мы имеем в виду анонимную функцию, также и наоборот.

При создании анонимной функции, возвращается экземпляр класса Closure, то есть анонимная функция только выглядит как функция, но на самом деле является экземпляром класса Closure.

Самое простое замыкание может выглядеть следующим образом:

$closure = function($name) {
return ‘Hello ’ . $name;
};
echo $closure(‘Mark’);

Данным примером мы создали объект замыкания, который присвоили переменной $closure, а затем вызвали функцию, которая как бы находится в переменной $closure.

Если мы попытаемся получить класс объекта $closure, то увидим, имя класса “Closure”

echo get_class($closure);

Результат

Closure

То есть создав анонимную функцию мы по сути создали экземпляр класса “Closure”. Если сказать грубо, то по факту мы занесли функцию в переменную, а поскольку у функции нет имени, но она располагается в переменной, мы можем вызвать функцию обратившись к переменной и поставив после ее имени круглые скобки.

Объект замыкания при реализации использует магический метод __invoke(), иначе говоря PHP вызывает метод __invoke() каждый раз когда видит круглые скобки после
имени переменной.

Но понятие “Замыкание” на этом не заканчивается. Если у вас есть фундаментальные знания о языке PHP, вы должно быть уже знаете, что доступ к переменным внутри анонимной функции ограничивается самой функцией, иначе говоря в теле созданной нами анонимной функции мы не можем просто так получить доступ к внешней области видимости (внешним переменным). Да, мы можем передать внешнее через аргументы, но такой способ не всегда может оказаться подходящим.

Замыканием можно также назвать механизм, который позволит взаимодействовать с переменными вне ее локальной области видимости. Например

$word = 'Hello ';
$closure = function($name) {
return $word . $name;
};
echo $closure('John');

Результат:

PHP Notice: Undefined variable: word in closure.php on line 6
John

В первую очередь PHP нам выдаст ошибку уровня “Notice”, повествующую о том, что переменная “word” не определена. Произошло это потому, что анонимная функция ничего не знает о внешнем окружении или иначе говоря о родительской области видимости. Затем PHP выведет строку “John”, то есть значение переданного ей аргумента. Но ведь мы ожидаем строку “Hello John”, неправда ли?

Для того, чтобы сделать переменную “word” доступной в рамках анонимной функции, ее нужно так скажем “импортировать” или иначе говоря “прокинуть” в эту самую функцию. Делается это при помощи оператора “use”

$word = 'Hello ';
$closure = function($name) use ($word) {
return $word . $name;
};
echo $closure('John');

Результат:

Hello John

Также необходимо отметить, что “прокинув” переменную “word” в область видимости анонимной функции, передалась она не по ссылке, а просто была скопирована. Иначе говоря если мы попытаемся изменить значение переменной “word” в теле анонимной функции, она поменяется исключительно в рамках этой анонимной функции:

$word = 'Hello ';
$closure = function($name) use ($word) {
$word = 'Hi ';
    return $word . $name;
};
echo $closure('John');
echo ' ' . $word;

Результат:

Hi John Hello

Если мы хотим, чтобы переменную “word” из родительской области видимости можно было изменить в рамках анонимной функции, то эту самую переменную нужно передать по ссылке при помощи оператора “&”

$word = 'Hello ';
$closure = function($name) use (&$word) {
$word = 'Hi ';
    return $word . $name;
};
echo $closure('John');
echo ' ' . $word;

Результат:

Hi John Hi

Информация

Автор конспекта


Дата создания: 02.01.2019
Категория: Веб-разработка