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). В этом случае класс называется вызываемым .

  • Замыкания считаются первоклассными типами значений , как и stringor integer. Это на самом деле секрет. Закрытие — это тип, определенный в движке 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. Надеюсь, вы были достаточно близки с ними. Анонимные функции всегда сложны для понимания и использования.

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

Я также признаю, что не могу сказать/объяснить все. Если у вас есть плюс, пожалуйста, добавьте его под этим уроком в качестве комментария. Спасибо за чтение.

 

 

 

 

 

Афоризм дня:
Мужество – добродетель, в силу которой люди в опасностях совершают прекрасные дела. (531)

Leave a reply