Determining if closure is static in PHP

A closure defined in PHP may also contain a static modifier.

 $f = function () { }; $g = static function () { }; 

Static closure cannot be bound using Closure::bind or Closure::bindTo and generates 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 it is annoying, it is acceptable; However, how to test static and non-static closure?

ReflectionMethod::isStatic seemed like this might work, but reasonably not like Closure::__invoke is an instance level and not static.

 $f = static function () { }; // reflect Closure::__invoke because I think I'm tricky $r = new ReflectionMethod($f, '__invoke'); // and it not static anyway var_dump($r->isStatic()); // bool(false) 

In addition, checking ReflectionMethod::getClosureThis may generally work, since the static method must be unbound, however this does not cover closures defined outside the instance method, or the corner case of instance methods that were 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 bound to nothing, as would be the case of a static closure var_dump($r->getClosureThis()); // NULL 

So, to confirm, how do you determine if a closure is static (or, more specifically, bound) or not?

It seems that we should have ReflectionFunctionAbstract::isBindable or ReflectionMethod::isStatic navigate to ReflectionFunctionAbstract .

+6
source share
2 answers

If the binding works, Closure will have $ this binding to it. So just bind it and then check the value of $ this. If this is a null value, then this is a static closure.

 function isBindable(\Closure $closure) { return (new ReflectionFunction(@\Closure::bind($closure, new stdClass)))->getClosureThis() != null; } 
+5
source

Now it seems impossible.
You can find some discussions here: https://bugs.php.net/bug.php?id=64761
The only real workaround that I am using for myself right now is to manually add the ->isBindable .

Here is the code I found here https://github.com/atoum/atoum/blob/master/classes/test/adapter/invoker.php
Perhaps you will give some 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; } 
+2
source

Source: https://habr.com/ru/post/981284/


All Articles