【发布时间】:2011-05-06 21:23:19
【问题描述】:
PHP manual for anonymous functions(即闭包)声明:
匿名函数目前是使用闭包类实现的。这是一个实现细节,不应依赖。
(重点是我自己的)
是否可以测试一个变量,使得只有当变量是一个闭包时测试才返回真,不参考闭包类?
换句话说,当$bar 不是匿名函数时,我该如何重写以下代码以引发错误:
函数 foo(闭包 $bar) {
$bar();
}
编辑:根据收到的答案,这是一个示例测试。
注意事项:
- 似乎没有办法区分函子和闭包,而且 该测试可能与使用 Closure 类一样“特定于实现”。
- (看起来很明显)
ReflectionFunction::isClosure()方法似乎几乎没用:当您完成所需的检查以确保 ReflectionFunction 可以实际实例化时(除了闭包,不能使用类) ,您已经排除了所有其他选项。 - 在 5.3.0 中,您的 ReflectionClass($closure)->hasMethod('__invoke') 返回 false,因此这可以用作针对 Functor 的测试,但是(有人告诉我)这已经改变了。这也凸显了解决方案的脆弱性。
- 从 Gordon 跟进 - 从 PHP 5.4 开始,您可以依赖 Closure 作为一个 Closure:php.net/manual/en/class.closure.php
代码:
/**
* Return true if and only if the passed argument is a Closure.
*/
function testClosure($a) {
// Must be Callback, Labmda, Functor or Closure:
if(!is_callable($a)) return false;
// Elminate Callbacks & Lambdas
if(!is_object($a)) return false;
// Eliminate Functors
//$r = new ReflectionFunction($a); <-- fails if $a is a Functor
//if($r->isClosure()) return true;
return false;
}
测试用例:
//////////// TEST CASE /////////////
class CallBackClass {
function callBackFunc() {
}
}
class Functor {
function __invoke() {
}
}
$functor = new Functor();
$lambda = create_function('', '');
$callback = array('CallBackClass', 'callBackFunc');
$array = array();
$object = new stdClass();
$closure = function() { ; };
echo "Is it a closure? \n";
echo "Closure: " . (testClosure($closure) ? "yes" : "no") . "\n";
echo "Null: " . (testClosure(null) ? "yes" : "no") . "\n";
echo "Array: " . (testClosure($array) ? "yes" : "no") . "\n";
echo "Callback: " . (testClosure($callback) ? "yes" : "no") . "\n";
echo "Labmda: " .(testClosure($lambda) ? "yes" : "no") . "\n";
echo "Invoked Class: " . (testClosure($functor) ? "yes" : "no") . "\n";
echo "StdObj: " . (testClosure($object) ? "yes" : "no") . "\n";
-
【问题讨论】:
-
使用
create_function创建的函数怎么样,PHP 5.3 之前穷人的匿名函数?可以是__invoke()d 的对象呢? -
我对您是否可以测试闭包特别感兴趣(“...仅当变量是闭包时才返回真...”)
-
我的问题是你为什么要区分函子(或当时的任何回调)和闭包?在 5.3 中,从您的角度来看没有什么不同(因为您无法重新绑定任何东西),那有什么关系呢?如果通过
is_callable(),那为什么还不够??? -
从 PHP 5.4 开始,您可以依赖 Closure 作为一个 Closure:php.net/manual/en/class.closure.php
-
@Gordon 感谢您的跟进!我会在上面添加它。