A closure defined in PHP can also carry the static modifier.
$f = function () { };
$g = static function () { };
The static closure cannot be bound via Closure::bind or Closure::bindTo, and will issue a warning.
$g = Closure::bind(static function () { }, new stdClass());
// Warning: Cannot bind an instance to a static closure in ...
This is also the case of closures created by reflecting a static method with 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 ...
While annoying, this is acceptable; however, how is one to test between a static and non-static closure?
ReflectionMethod::isStatic seemed like it might work, but sensibly doesn't as Closure::__invoke is instance-level, not static.
$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)
Further, checking ReflectionMethod::getClosureThis can generally work, as a static method must be unbound, however that doesn't cover closures defined outside an instance method, or the corner-case of instance methods that have been unbound.
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
So, to restate, how do you determine whether a closure is static (or more specifically, bindable) or not?
It really seems as though we should have a ReflectionFunctionAbstract::isBindable, or that ReflectionMethod::isStatic be moved up to ReflectionFunctionAbstract.
It seems impossible now.
You can find some debates here: https://bugs.php.net/bug.php?id=64761
The only real workaround I use for myself now is adding ->isBindable property manually.
Here's some code I found here https://github.com/atoum/atoum/blob/master/classes/test/adapter/invoker.php
Maybe will give you a few ideas
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;
    }
                        If binding works, the Closure will have a $this bound to it. So, just bind it and then check for the $this. If it's null, well, then it's a static Closure.
function isBindable(\Closure $closure) {
    $boundClosure = @\Closure::bind($closure, new stdClass);
    return $boundClosure && (new ReflectionFunction($boundClosure))->getClosureThis() != null; 
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With