如何调用包含使用$ this的闭包的ReflectionFunction?

时间:2016-11-23 19:07:43

标签: php reflection

最简单的解释一个例子:

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

1 个答案:

答案 0 :(得分:1)

好吧,我真的不知道为什么会发生这种行为。但是有一个解决方法(好吧,我经过几次测试后发现它。)

由于PHP不允许您明确$thisit'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.45.55.67上进行了测试。

<强>更新

在@mpen回答之后,我意识到他的限制和反思的使用。

当您使用ReflectionFunction来调用至少function的{​​{1}}时,您应该将其视为closureReflectionFunction有一个名为ReflectionFunction::getClosure()的方法。

Class仍然是@mpen创建的,使用方式如下:

closure

但仅适用于$ex = new Example(); $f = new ReflectionFunction($ex->f); $closure = $f->getClosure(); echo $closure().PHP_EOL;

对于PHP 7PHP 5.45.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