Как я могу вызвать функцию ReflectionFunction, закрывающую закрытие, которое использует $ this?

Это проще всего объяснить на примере:

class Example { private $x; public $f; public function __construct() { $this->x = 10; $this->f = function() { return $this->x; }; } } $ex = new Example(); $f = new ReflectionFunction($ex->f); echo $f->invoke().PHP_EOL; 

Выполнение этого приводит к ошибке:

PHP Неустранимая ошибка: Непринятая ошибка: использование $ this, если не в контексте объекта

Это потому, что я использовал $this в закрытии, поэтому он больше похож на ReflectionMethod , но ReflectionMethod , похоже, не хочет принимать closure в качестве аргумента, поэтому я не совсем уверен, что я могу сделать.

Как я могу использовать $ex->f используя отражение?

Ну, я действительно не знаю, почему такое поведение происходит. Но есть обходной путь (ну, я нашел его после нескольких тестов).

Поскольку PHP не позволяет вам явно связывать $ this ( он связан автоматически ), вам нужно использовать альтернативную переменную:

 $t = $this; $this->f = function() use ($t) { return $t->x; }; 

Весь код:

 class Example { private $x; public $f; public function __construct() { $this->x = 10; $t = $this; $this->f = function() use ($t) { return $t->x; }; } } $ex = new Example(); $f = new ReflectionFunction($ex->f); echo $f->invoke().PHP_EOL; 

И результат хотел

 10 

Протестировано на PHP 5.4, 5.5, 5.6 и 7.

ОБНОВИТЬ

После ответа mpen я понял о его ограничениях и реальном использовании Reflection.

Когда вы используете функцию ReflectionFunction для вызова функции, которая по крайней мере является закрытием, вы должны рассматривать это как закрытие. Функция ReflectionFunction имеет метод getClosure ().

Класс остается таким, как mpen, и его использование будет следующим:

 $ex = new Example(); $f = new ReflectionFunction($ex->f); $closure = $f->getClosure(); echo $closure().PHP_EOL; 

Но работает только на PHP 7.

Для PHP 5.4, 5.5 и 5.6 вам потребуется привязать класс и область действия. Странно, но это единственный способ, который я нашел, используя Closure :: bindTo () или Closure :: bind () :

 $ex = new Example(); $f = new ReflectionFunction($ex->f); $closure = $f->getClosure(); $class = $f->getClosureThis(); $closure = $closure->bindTo($class , $class); echo $closure().PHP_EOL; 

Или просто:

 $ex = new Example(); $f = new ReflectionFunction($ex->f); $class = $f->getClosureThis(); $closure = Closure::bind($f->getClosure() , $class , $class); echo $closure().PHP_EOL; 

Это важно передать класс как область действия (второй параметр), который определит, можете ли вы получить доступ к частной / защищенной переменной или нет.

Второй параметр также может быть именем класса как:

 $closure = $closure->bindTo($class , 'Example');//PHP >= 5.4 $closure = $closure->bindTo($class , get_class($class));//PHP >= 5.4 $closure = $closure->bindTo($class , Example::class);//PHP 5.5 

Но я не беспокоился о производительности, поэтому класс прошел в два раза хорошо для меня.

Существует также метод Closure :: call (), который можно использовать для изменения области, но также и для PHP> = 7.