在 PHP 中判断一个闭包是不是是静态的

Posted

技术标签:

【中文标题】在 PHP 中判断一个闭包是不是是静态的【英文标题】:Determining if a closure is static in PHP在 PHP 中判断一个闭包是否是静态的 【发布时间】:2015-03-18 19:36:12 【问题描述】:

php 中定义的闭包也可以带有static 修饰符。

$f = function ()  ;

$g = static function ()  ;

静态闭包不能通过Closure::bindClosure::bindTo绑定,会发出警告。

$g = Closure::bind(static function ()  , new stdClass());

// Warning: Cannot bind an instance to a static closure in ...

这也是通过使用ReflectionMethod::getClosure 反射静态方法创建的闭包的情况。

class MyClass

    public static function myStaticMethod()  


// reflect MyClass::myStaticMethod,  create an unbound closure, and try to bind it
$f = (new ReflectionMethod(MyClass::class, 'myStaticMethod'))
    ->getClosure()
    ->bindTo(new stdClass());

// Warning: Cannot bind an instance to a static closure in ...

虽然烦人,但这是可以接受的; 但是,如何在静态闭包和非静态闭包之间进行测试?

ReflectionMethod::isStatic 看起来它可能可以工作,但显然不是因为Closure::__invoke 是实例级的,而不是静态的。

$f = static function ()  ;

// reflect Closure::__invoke because I think I'm tricky
$r = new ReflectionMethod($f, '__invoke');

// and it's not static anyway
var_dump($r->isStatic()); // bool(false)

此外,检查ReflectionMethod::getClosureThis 通常可以工作,因为静态方法必须是未绑定的,但这不包括在实例方法之外定义的闭包,或已未绑定。

class MyClass

    public function myInstanceMethod()  


$o = new MyClass();

// reflect MyClass::myInstanceMethod, create a bound closure, and then unbind it
$f = (new ReflectionMethod($o, 'myInstanceMethod'))
    ->getClosure($o)
    ->bindTo(null);

// then reflect the closure
$r = new ReflectionFunction($f);

// and see it's bound to nothing, as would be the case of a static closure
var_dump($r->getClosureThis()); // NULL

所以,重申一下,您如何确定闭包是否是静态的( 或者更具体地说,是可绑定的)?

看起来我们真的应该有一个ReflectionFunctionAbstract::isBindable,或者ReflectionMethod::isStatic 被移动到ReflectionFunctionAbstract

【问题讨论】:

【参考方案1】:

如果绑定有效,闭包将绑定一个 $this。所以,只需绑定它,然后检查 $this。如果它为空,那么它就是一个静态闭包。

function isBindable(\Closure $closure) 
    $boundClosure = @\Closure::bind($closure, new stdClass);

    return $boundClosure && (new ReflectionFunction($boundClosure))->getClosureThis() != null; 

【讨论】:

这是我目前看到的唯一方法。 同样如此。我不喜欢它因为@ 而变得肮脏,但它工作可靠,而且我找不到任何极端情况。【参考方案2】:

现在看来不可能了。 你可以在这里找到一些辩论:https://bugs.php.net/bug.php?id=64761 我现在为自己使用的唯一真正的解决方法是手动添加 ->isBindable 属性。

这是我在这里找到的一些代码 https://github.com/atoum/atoum/blob/master/classes/test/adapter/invoker.php 也许会给你一些想法

protected static function isBindable(\closure $closure)
    
        $isBindable = (version_compare(PHP_VERSION, '5.4.0') >= 0);
        if ($isBindable === true)
        
            $reflectedClosure = new \reflectionFunction($closure);
            $isBindable = ($reflectedClosure->getClosureThis() !== null || $reflectedClosure->getClosureScopeClass() === null);
        
        return $isBindable;
    

【讨论】:

这不处理它是可绑定的情况,但没有绑定到任何东西,也没有范围类。

以上是关于在 PHP 中判断一个闭包是不是是静态的的主要内容,如果未能解决你的问题,请参考以下文章

Groovy闭包 Closure ( 闭包类 Closure 简介 | thisownerdelegate 成员区别 | 静态闭包变量 | 闭包中定义闭包 )

PHP静态化技术

PHP Closure(闭包)类详解

PHP Closure(闭包)类详解

php中怎么理解Closure的bind和bindTo

lambda 函数和闭包(在 PHP 中)之间的区别?