Пользовательские обработчики с использованием объекта $this (методы bindTo и bind в замыканиях)
15 июля 2018
Документация по bindTo: https://www.php.net/manual/ru/closure.bindto.php
Документация по bind: https://www.php.net/manual/ru/closure.bind.php
Пользовательские обработчики, реализуемые через замыкания (анонимные функции), за пределами класса в теле функции не могут использовать свойства и методы текущего объекта. Но им можно разрешить это делать с помощью метода bindTo($obj, $scope) класса замыканий Closure.
Данный метод создаёт и возвращает копию замыкания с передачей в функцию объекта и новой области доступа. К переданному объекту (аргумент $obj) в теле функции можно обращаться через ключевое слово $this.
Аргумент $scope определяет имеет ли функция доступ к защищённым (protected) и закрытым (private) свойствам и методам объекта. Если в аргументе указать название класса, то функции будет разрешён доступ к защищённым и закрытым структурам объекта, а если в аргументе указать строчное значение static, то область видимости останется без изменений и функция будет иметь доступ только к открытым (public) свойствам и методам.
Пример кода:
Существует статический метод bind($closure, $obj, $scope), который повторяет функциональность bindTo. В аргументе $closure указывается замыкание.
Пример использования:
Документация по bind: https://www.php.net/manual/ru/closure.bind.php
Пользовательские обработчики, реализуемые через замыкания (анонимные функции), за пределами класса в теле функции не могут использовать свойства и методы текущего объекта. Но им можно разрешить это делать с помощью метода bindTo($obj, $scope) класса замыканий Closure.
Данный метод создаёт и возвращает копию замыкания с передачей в функцию объекта и новой области доступа. К переданному объекту (аргумент $obj) в теле функции можно обращаться через ключевое слово $this.
Аргумент $scope определяет имеет ли функция доступ к защищённым (protected) и закрытым (private) свойствам и методам объекта. Если в аргументе указать название класса, то функции будет разрешён доступ к защищённым и закрытым структурам объекта, а если в аргументе указать строчное значение static, то область видимости останется без изменений и функция будет иметь доступ только к открытым (public) свойствам и методам.
Пример кода:
final class Hello
{
private $ru = 'Привет'; //русский
private $en = 'Hi'; //английский
private $de = 'Guten Tag'; //немецкий
private $hy = 'Բարեւ'; //армянский
private $procedure = false; //Обработчик вывода
function __construct()
{
//Вывод по-умолчанию
$this->procedure = function()
{
echo $this->ru.'<br>';
};
}
// Устанавливает новый (если задан) и вызывает обработчик вывода
// @param object|bool - новый обработчик или false, если обработчик не нужно менять
public function write_1($func=false)
{
//Установка нового обработчика
if(is_object($func))
{
$this->procedure = $func->bindTo($this, __CLASS__);
}
//Вызов обработчика
if(is_callable($this->procedure))
{
/*
Если вызвать замыкание из свойства просто как $this->procedure, то интерпретатор ничего не выведет.
А если вызвать замыкание как $this->procedure(), то будет ошибка, что метода не существует.
Поэтому замыкание в свойстве нужно выводить, обводя свойство в скобки
*/
($this->procedure)();
}
}
// Устанавливает новый (если задан) и вызывает обработчик вывода
// @param object|bool - новый обработчик или false, если обработчик не нужно менять
public function write_2($func=false)
{
//Установка нового обработчика
if(is_object($func)) $this->procedure = $func;
//Вызов обработчика
if(is_callable($this->procedure)) ($this->procedure)();
}
}
$a = new Hello();
//Выведет 'Привет'
$a->write_1();
//Выведет 'Hi'
$a->write_1(function(){
echo $this->en.'<br>';
});
/*
Выведет ошибку 'Uncaught Error: Using $this when not in object context', так как тело функции
не видит переменную $this. Для того, что бы функция видела объект нужно создавать копию функции с передачей объекта.
Всё это делается через метод bindTo
*/
$a->write_2(function(){
echo $this->de.'<br>';
});
Статический bind
В предыдущем примере сначала создавалась анонимная функции, а затем для неё вызывался метод bindTo.Существует статический метод bind($closure, $obj, $scope), который повторяет функциональность bindTo. В аргументе $closure указывается замыкание.
Пример использования:
class Day
{
private $str = 'День';
}
$a = new Day();
$b = Closure::bind(function(){
echo 'Хороший '.$this->str;
}, $a, 'Day');
$b(); //Выведет 'Хороший День'