Страницы

Поиск по вопросам

вторник, 28 мая 2019 г.

Статические анонимные функции в PHP

Где и как они могут быть использованы?
Еще интересует такая конструкция:
Взято из документации
new class { function __construct() { (static function() { var_dump($this); })(); } };
В целом неясно что значит new class, почему статическая функция заключена в круглые скобки и почему после этой функции стоят круглые скобки дополнительно И как все это работает без создания объекта (У меня есть некоторые догадки по некоторым вопросам, но нужно чтобы они подтвердились или опроверглись)
Есть еще один пример то же не ясно что за зверь:
(static function() { // function body })->call(new StdClass);
P.S Пытался узнать что это такое но так и не нашел, надеюсь на помощь прошаренных людей в данной области


Ответ

Давайте по порядку, а то у вас под одним заголовком много разных несвязанных между собой вопросов.
new class
new class - в PHP 7.0 добавили поддержку анонимных классов. То же самое, что и анонимная функция, но уже класс.
(function(){/**/})();
Повсеместное явление в JS, странно, что ранее вам такого не попадалось. То что не попадалось в PHP - вполне логично, эту возможность парсеру добавили опять же в PHP7.0 только. Всё просто, здесь создаётся анонимная функция и тут же вызывается
(function() { echo 'body'; })();
Этот фрагмент PHP 7.0. Более явным образом (и совместимым со старыми PHP5.3 и старше) можно записать так:
$fn = function() { echo 'body'; };
$fn();
Либо
call_user_func(function() { echo 'body'; });
В общем, способов вызвать функцию есть много.
static function() {}
Эта штука довольно старая, добавлена в PHP5.4. Объявление анонимной функции в контексте объекта на самом деле привязывает функцию к этому объекту как новый метод (совместимый с PHP5.4 пример, в отличии от данного в мануале только для PHP7.0 и более запутанного):
class test { private $foo = 'bar';
function __construct() { call_user_func(function() { var_dump($this->foo); }); } };
new test;
Ключевое слово static же заставляет создать функцию, которая себя ведёт как статический метод, к $this уже доступа не имеет:
class test { private static $foo = 'bar';
function __construct() { call_user_func(static function() { var_dump(self::$foo); }); } };
new test;
При этом для самого класса статический метод не добавляется, это всё так же анонимная функция.
(function() {})->call()
На самом деле, (function() {}) создаёт не только функцию, которую можно вызвать, а конструирует объект служебного класса Closure. В PHP 5.4 этот класс научился нескольким методам, которые можно вызывать, будто функция - это объект, потому что на самом деле это и есть объект. Метод call (опять же в PHP 7.0 добавлен) позволяет вызвать анонимную функцию в контексте указанного объекта или статическим методом класса:
Не надо, пожалуйста, так делать в реальном коде! Но для ответа на вопрос я это показать обязан.
class test { private $foo = 'bar'; };
$obj = new test; $fn = function() { var_dump($this->foo); }; $fn->call($obj);
Внимание на private поле, которое мы легко и непринуждённо читаем извне класса. Да, получить доступ к private полю извне класса и даже записать туда что-нибудь - легче лёгкого с давнего PHP 5.4, когда появились методы bind и bindTo.
Итого
Первый фрагмент кода в вопросе:
new class { function __construct() { (static function() { var_dump($this); })(); } };
Иллюстрация как делать не надо. static function к this доступа иметь не будет. PHP7.0.0 скажет E_NOTICE Undefined variable: this, а PHP 7.1 вовсе выбросит Throwable Error с текстом Using $this when not in object context
Объект создаётся непосредственно при new class, объект анонимного класса.
Второй фрагмент:
(static function() { // function body })->call(new StdClass);
Так же демонстрирует код, который работать не будет. К методу, объявленному static невозможно ассоциировать объект - а именно это перед непосредственно вызовом функции и делает метод call. Результатом будет E_WARNING Cannot bind an instance to a static closure (и в 7.0 и в 7.1, скорей всего будет изменено на Throwable Error позже)

Комментариев нет:

Отправить комментарий