2016-11-23 22 views
0

这是最简单的用一个例子来解释:

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 Fatal error: Uncaught Error: Using $this when not in object context

那是因为我已经用在封闭$this,所以它看起来更像一个ReflectionMethod ,但ReflectionMethod似乎并不想以closure作为参数,所以我不确定我能做什么。

如何使用反射调用$ex->f

回答

1

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

由于PHP不要让你明确的$这个(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.

UPDATE

MPEN的答案后,我意识到他的限制和实际使用反射。

当您使用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; 

这是版本关口班级为范围(第二个参数),这将决定是否您可以访问私有/受保护的变量或不。

第二paramater也可以是类名称为:

$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

+0

谢谢,但这不是真正的我一个解决方案。我需要能够调用任意关闭。 – mpen

+0

@mpen我已经更新了所有我测试过的问题 –