最简单的解释一个例子:
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
?
答案 0 :(得分:1)
好吧,我真的不知道为什么会发生这种行为。但是有一个解决方法(好吧,我经过几次测试后发现它。)
由于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
的{{1}}时,您应该将其视为closure
。 ReflectionFunction
有一个名为ReflectionFunction::getClosure()
的方法。
Class仍然是@mpen创建的,使用方式如下:
closure
但仅适用于$ex = new Example();
$f = new ReflectionFunction($ex->f);
$closure = $f->getClosure();
echo $closure().PHP_EOL;
。
对于PHP 7
,PHP 5.4
和5.5
,您必须绑定类和范围。很奇怪,但这是我使用Closure::bindTo()或Closure::bind()找到的唯一方式:
5.6
或者只是:
$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::call()可用于更改范围,但也适用于$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
。