tiene - php etiquetas html
Determinar si un cierre es estático en PHP (2)
Parece imposible ahora.
Puede encontrar algunos debates aquí: https://bugs.php.net/bug.php?id=64761
La única solución real que uso ahora es añadir ->isBindable
propiedad ->isBindable
manual.
Aquí hay un código que encontré aquí https://github.com/atoum/atoum/blob/master/classes/test/adapter/invoker.php
Tal vez le dará algunas 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;
}
Un cierre definido en PHP también puede llevar el modificador static
.
$f = function () { };
$g = static function () { };
El cierre estático no puede vincularse mediante Closure::bind
o Closure::bindTo
, y emitirá una advertencia.
$g = Closure::bind(static function () { }, new stdClass());
// Warning: Cannot bind an instance to a static closure in ...
Este es también el caso de los cierres creados al reflejar un método estático con 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 ...
Aunque molesto, esto es aceptable; sin embargo, ¿cómo se debe probar entre un cierre estático y no estático?
ReflectionMethod::isStatic
parecía que podría funcionar, pero con sensatez no es porque Closure::__invoke
es a nivel de instancia, no estático.
$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)
Además, comprobar ReflectionMethod::getClosureThis
generalmente puede funcionar, ya que un método estático debe ser independiente, sin embargo, eso no cubre los cierres definidos fuera de un método de instancia, o el caso de esquina de los métodos de instancia que han sido desatados .
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
Entonces, para replantear, ¿cómo se determina si un cierre es estático ( o más específicamente, vinculable ) o no?
Realmente parece que deberíamos tener un ReflectionFunctionAbstract::isBindable
, o que ReflectionMethod::isStatic
se mueva hasta ReflectionFunctionAbstract
.
Si el enlace funciona, el Cierre tendrá $ a esto vinculado. Entonces, solo agréguela y luego revise por $ this. Si es nulo, bueno, entonces es un Cierre estático.
function isBindable(/Closure $closure) {
return (new ReflectionFunction(@/Closure::bind($closure, new stdClass)))->getClosureThis() != null;
}