嗯,我真的不知道为什么会发生这种行为。但是有一个解决方法(好吧,我在几次测试后找到了它)。
由于PHP 不允许您显式绑定$this (it's bound automatically),您必须使用替代变量:
$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 回答后,我意识到他的限制和反射的使用。
当您使用ReflectionFunction 调用function(至少是closure)时,您应该将其视为closure。 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;
将类作为范围(第二个参数)传递非常重要,这将决定您是否可以访问private/protected 变量。
第二个参数也可以是类名:
$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。