在 PHP 中确定闭包是否是静态的
Determining if a closure is static in PHP
PHP 中定义的闭包也可以带有 static
修饰符。
$f = function () { };
$g = static function () { };
静态闭包无法通过Closure::bind
or Closure::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
。
现在看来不可能了
你可以在这里找到一些争论: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;
}
如果绑定有效,闭包将绑定一个 $this。所以,只需绑定它,然后检查 $this。如果它是 null,那么它就是一个静态闭包。
function isBindable(\Closure $closure) {
$boundClosure = @\Closure::bind($closure, new stdClass);
return $boundClosure && (new ReflectionFunction($boundClosure))->getClosureThis() != null;
}
PHP 中定义的闭包也可以带有 static
修饰符。
$f = function () { };
$g = static function () { };
静态闭包无法通过Closure::bind
or Closure::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
。
现在看来不可能了
你可以在这里找到一些争论: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;
}
如果绑定有效,闭包将绑定一个 $this。所以,只需绑定它,然后检查 $this。如果它是 null,那么它就是一个静态闭包。
function isBindable(\Closure $closure) {
$boundClosure = @\Closure::bind($closure, new stdClass);
return $boundClosure && (new ReflectionFunction($boundClosure))->getClosureThis() != null;
}