
PHP
Погружение в Closure и анонимные функции в PHP
Замыкания и анонимность - это то, что мне было трудно изучить во всей экосистеме PHP, не потому, что я, вероятно, сошел с ума, а потому, что нет хорошего и подробного объяснения того, что именно они собой представляют и как их можно использовать.
Я решил покопаться и посмотреть, смогу ли я понять, что такое замыкания в PHP. Здесь я поделюсь с вами, как я это сделал и что я нашел. Хотя мой метод может показаться некоторым из вас ненаучным, я попробовал личную процедуру, на оттачивание которой у меня не ушло много времени.
Что такое анонимная функция?
Безымянная функция . _ Анонимная функция выглядит так:
function($x){
return $x * 2;
}
Нормальная функция:
function timesTwo($x){
return $x * 2;
}
В отличие от обычных функций, анонимная функция не имеет имени.
Теперь представьте, если вы хотите использовать анонимную функцию, как вы это сделаете? в основном (можно использовать в функциях первого класса) это невозможно сделать. Итак, чтобы помочь в этом, реализована привязка имени, позволяющая хранить всю анонимную функцию в файле variable
. Когда это сделано, это variable
становится тем, что называется Closure
Что такое замыкание в PHP?
Класс , который ( тип ) используется для представления анонимной функции . Это может звучать очень странно, в PHP есть встроенный класс Closure . Когда создается анонимная функция, ее тип автоматически равен object(Closure)
. Помните о динамической типизации PHP. Вот почему на практике Closure является анонимной функцией .
Чтобы доказать это, попробуйте следующее:
var_dump(function($x){
return $x * 2;
});
Переменная , содержащая анонимную функцию
Когда анонимная функция связана с переменной, эта переменная становится объектом класса Closure , следовательно, также является функцией Closure/anonymous .
На пути понимания этого
Во-первых, попробуйте создать объект/экземпляр класса Closure .
$closure = new Closure();
Мы получаем это:
PHP Catchable fatal error: Instantiation of 'Closure' is not allowed
Это объясняется этим:
- Класс Closure не предназначен для создания экземпляров; его конструктор имеет значение
private
. - Класс ничего не возвращает и не имеет параметров.
Некоторые факты об этом классе
- У него всего 5 методов:
__construct()
,__invoke()
,bindTo()
,call()
,bind()
- Метод
__construct()
существует только для того, чтобы запретить создание экземпляра класса - Это точно не интерфейс
- Класс является окончательным
Небольшое пояснение
Нам не нужно создавать экземпляр Closure , так как PHP делает это каждый раз, когда функция создается без имени, поэтому теперь я могу сделать:
function()
{
return true;
}
Проблема как его так использовать??
Решение, создайте переменную и сохраните функцию, затем, используя переменную, мы вызываем функцию:
$closureFunction = function()
{
return true;
}; //never forget this semi-colon
Теперь, поскольку это (выглядит) как переменная, мы должны иметь возможность использовать ее разными способами, например, повторяя ее, используя ее в качестве параметра функции или свойства класса и т. д.
-- С echo()
echo $closureFunction; // PHP Catchable fatal error: Object of class Closure could not be converted to string;
-- Как функция
echo test($closureFunction); //PHP Catchable fatal error: Object of class Closure could not be converted to string
Независимо от того, где вы пытаетесь echo
это сделать, вы всегда будете получать эту ошибку. Чтобы доказать это, давайте var_dump
посмотрим, что мы пытаемся повторить:
var_dump($closureFunction);
var_dump(test($closureFunction));
Результат:
object(Closure)#1 (0) { }
object(Closure)#1 (0) { }
Переменная, содержащая нашу nameless
функцию, на самом деле содержит объект типа Closure .
Что произошло, как функция превратилась в объект?
Прежде чем я отвечу, давайте копнем дальше, установив параметр функции:
$closureFunction = function($var)
{
return $var;
};
function test($var)
{
return $var;
}
var_dump($closureFunction); // object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
var_dump($closureFunction('ok')); // string(2) "ok"
echo($closureFunction('ok')); // ok
var_dump(test($closureFunction)); //object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
var_dump(test($closureFunction('ok'))); // string(2) "ok"
var_dump(test($closureFunction($closureFunction))); // object(Closure)#1 (1) { ["parameter"]=> array(1) { ["$var"]=> string(10) "" } }
Отсюда пока:
- функция
nameless
находится в переменной - мы можем использовать его где угодно, так как можно использовать переменную, кроме ее повторения
- функция становится объектом класса Closure
Объяснение магии:
-
Тот факт, что класс Closure реализует
__invoke
, означает, что мы можем вызывать его экземпляры как вызов функции, например$var()
.Если this:
$var = function(){};
является объектом Closure , он позволяет нам использовать его$var
с таким параметром, как$var($parameter)
. В этом случае класс называется вызываемым . -
Замыкания считаются первоклассными типами значений , как и
string
orinteger
. Это на самом деле секрет. Закрытие — это тип, определенный в движке PHP как тип, и вы не видите, когда именно они генерируются.
Какая польза?
Их использование зависит в основном от вашего варианта использования и потребностей. Тем не менее, вы можете использовать их как:
-- Callables/Callback работают следующим образом:
$items = [1, 2];
$closure = function($x, $y){
echo __FUNCTION__, " got $x and $y";
};
call_user_func_array ($closure , $items );
-- Наследование переменных , подобное этому:
$msg = 'Hello';
$closure = function () use ($msg) {
var_dump($msg);
};
$closure();
-- Присвоение переменной
$eat = function($food){
echo "I am eating some ", $food."<br>";
};
$eat('Bananas');
$eat('Apples');
-- чтобы прикрепить состояние следующим образом:
function brand($name) {
return function ($slogan) use ($name){
return sprintf('%s : %s', $name, $slogan);
};
}
$brand = brand('Dell');
print $brand('The power to do more.');
-- Рекурсия
$recursive = function () use (&$recursive){
return $recursive;
} ;
print_r($recursive());
Некоторые практические варианты использования
- В большинстве современных фреймворков замыкания используются для маршрутизации.
- Закрытие также используется при разработке корзин для покупок.
Заключение
Это было исследование закрытий PHP. Надеюсь, вы были достаточно близки с ними. Анонимные функции всегда сложны для понимания и использования.
Что вы должны знать сейчас, так это то, что каждый раз, когда у вас возникает случай/проблема, просто помните и спрашивайте себя, могут ли замыкания быть очень полезными. Вы будете удивлены, как они облегчат вашу жизнь.
Я также признаю, что не могу сказать/объяснить все. Если у вас есть плюс, пожалуйста, добавьте его под этим уроком в качестве комментария. Спасибо за чтение.
Leave a reply