This is easiest to explain with an example:
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;
Running this results in an error:
PHP Fatal error: Uncaught Error: Using $this when not in object context
That's because I've used $this
in the closure, so it's really more like a ReflectionMethod
, but ReflectionMethod
doesn't seem to want to take a closure
as an argument, so I'm not really sure what I can do.
How can I invoke $ex->f
using reflection?
Well, I really don't know why that behavior is happening. But there's a workaround (well, I found it after a few tests).
As
PHP
doesn't let you explicit the bind of$this
(it's bound automatically), you have to use an alternative variable:The entire code:
And the result wanted
Tested on
PHP 5.4
,5.5
,5.6
and7
.UPDATE
After @mpen answer, I've realized about his restrictions and the use of Reflection.
When you use a
ReflectionFunction
to invoke afunction
, which is aclosure
at least, you should treat that as aclosure
.ReflectionFunction
has a method calledReflectionFunction::getClosure()
.The Class remains as @mpen created and the use will be as:
But only works on
PHP 7
.For
PHP 5.4
,5.5
and5.6
you'll have to bind the class and scope. Weird, but it's the only way that I found using Closure::bindTo() or Closure::bind():Or just:
It's very important to pass the class as scope (second parameter) which will determine whether you can access
private
/protected
variable or not.The second paramater also could be the class name as:
But I didn't concerned about performance, so the class passed twice is just fine to me.
There's also the method Closure::call() which can be used to change the scope, but also just for
PHP >= 7
.