Как связать $this с закрытием, которое передается как параметр метода в PHP 5.4?
Есть ли способ привязать $this
к закрытию, которое передается как параметр?
Я читал и перечитывал все, что мог найти в руководстве или через Интернет, но никто не упоминает об этом, кроме этого сообщения в блоге:
http://www.christophh.net/2011/10/26/closure-object-binding-in-php-54/
который упоминает об этом, но не показывает, как это сделать.
Итак, вот пример. При вызове метода get(function() {})
я хочу, чтобы функция обратного вызова, которая была передана ему, была привязана к объекту, то есть привязана к $this
, но, к сожалению, это не работает. Есть ли способ сделать это?
class APP
{
public $var = 25;
public function __construct() {
}
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Paran must be callable.');
}
// $callback->bindTo($this);
$callback->bindTo($this, $this);
$callback();
}
}
$app = new APP();
$app->get(function() use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($this);
});
$app
работает. $this
имеет значение NULL.
Ответы
Ответ 1
Я действительно не понял, почему использование метода bindTo
в этом случае не помогло, но я мог заставить его работать, используя Closure::bind
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$bound = Closure::bind($callback, $this);
$bound();
}
Edit
По-видимому, метод bindTo
имеет такое же поведение, поэтому вы должны переназначить его возвращаемое значение на $callback
. Например:
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$callback = $callback->bindTo($this);
$callback();
}
Ответ 2
Сделайте это так:
class APP
{
public $var = 25;
public function __construct() {}
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
// $callback->bindTo($this);
// you must save result in another var and call it
$callback1 = $callback->bindTo($this, $this);
$callback1();
}
}
$app = new APP();
$app->get(function() use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($this);
});
Ответ 3
Просто передайте его как аргумент:
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Paran must be callable.');
}
// $callback->bindTo($this);
return $callback($this);
}
...
$app = new APP();
$app->get(function($that) use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($that);
});
В качестве альтернативы, если вам действительно нужно связать его, вам нужно будет использовать функцию, которая возвращает функцию, например:
public function getCallback($callback) {
return function($app){
return $callback($this, $app);
}
}
...
$app = new APP();
$f = $app->get(function($that, $app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($that);
});
$f($app);
Ответ 4
Небольшая поправка: не используйте is_callable
, чтобы проверить, прошел ли Closure
по параметру.
Потому что is_callable
тоже принимает строку с именем функции.
public function get(\Closure $callback) {
$bound = \Closure::bind($callback, $this);
$bound();
}
С is_callable
мы имеем такую возможность:
$app = new App;
$app->get('my_function');
Если функция существует, эта ошибка возникает:
Closure:: bind() ожидает, что параметр 1 должен быть закрыт, строка задана
Потому что "My_function" передается в тесте is_callable
, но Closure::bind
ожидает экземпляр Closure
.