Well, I really don't know why this behavior is happening. But there is a workaround (well, I found it after several tests).
Since PHP does not allow you to explicitly bind $ this ( it is automatically bound ), you need to use an alternative variable:
$t = $this; $this->f = function() use ($t) { return $t->x; };
All code:
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;
And the result was like
10
Tested in PHP 5.4, 5.5, 5.6 and 7.
UPDATE
After mpen answered, I realized about its limitations and the actual use of Reflection.
When you use the ReflectionFunction function to call a function that is at least a closure, you should consider this as a closure. The ReflectionFunction function has a getClosure () method.
The class remains as mpen, and its use will be as follows:
$ex = new Example(); $f = new ReflectionFunction($ex->f); $closure = $f->getClosure(); echo $closure().PHP_EOL;
But it only works on PHP 7.
For PHP 5.4, 5.5 and 5.6 you will need to bind a class and scope. Strange, but this is the only way I found using Closure :: bindTo () or 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;
Or simply:
$ex = new Example(); $f = new ReflectionFunction($ex->f); $class = $f->getClosureThis(); $closure = Closure::bind($f->getClosure() , $class , $class); echo $closure().PHP_EOL;
It is important to pass the class as a scope (second parameter), which will determine if you can access the private / protected variable or not.
The second parameter can also be a class name:
$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
But I was not worried about performance, so the class went through twice, and I feel good too.
There is also a Closure :: call () method that can be used to change the scope, but also for PHP> = 7.