在不引用闭包内部类的情况下测试PHP闭包
(即关闭)声明: 匿名函数当前使用闭包类实现。这是一个实施细节,不应依赖于 (重点是我自己的) 是否可以测试一个变量,这样只有当变量是闭包时,测试才会返回true,,而不引用闭包类 换句话说,当在不引用闭包内部类的情况下测试PHP闭包,php,closures,Php,Closures,(即关闭)声明: 匿名函数当前使用闭包类实现。这是一个实施细节,不应依赖于 (重点是我自己的) 是否可以测试一个变量,这样只有当变量是闭包时,测试才会返回true,,而不引用闭包类 换句话说,当$bar不是匿名函数时,如何重写以下内容以使其产生错误: function foo(Closure $bar) { $bar(); } 测试用例: //////////// TEST CASE ///////////// class CallBackClass { function ca
$bar
不是匿名函数时,如何重写以下内容以使其产生错误:
function foo(Closure $bar) {
$bar();
}
测试用例:
//////////// 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";
-和!is_array
可能会帮助您。请注意,您不能依赖PHP的类型提示/检查,因为您必须检查函数中的变量并抛出一些东西,例如您自己抛出的InvalidArgumentException
。您也可以使用
-检查是否关闭
例如:
$poorMansLambda = create_function('', 'return TRUE;');
$rf = new ReflectionFunction($poorMansLambda);
var_dump( $rf->isClosure() ); // FALSE
$lambda = function() { return TRUE; };
$rf = new ReflectionFunction($lambda);
var_dump( $rf->isClosure() ); // TRUE
$closure = function() use ($lambda) { return $lambda(); };
$rf = new ReflectionFunction($closure);
var_dump( $rf->isClosure() ); // TRUE
请注意,对于PHP5.3 Lambdas和闭包,上面只返回TRUE
。如果您只想知道某个参数是否可以用作回调,是可调用的
将执行得更好
编辑如果还想包含函子,可以执行() 或 后者是更快的选择
闭包
实例基本上只是一个类,它有一个\u invoke
函数,您可以动态地将该函数提供给方法体。但由于这是对实现细节的测试,我认为这和测试闭包类名一样不可靠
编辑既然您提到无法通过反射API进行可靠的测试,因为它在将函子传递给反射函数stretc::isClosure
时会引发错误,请尝试以下解决方案以满足您的需要:
function isClosure($arg)
{
if(is_callable($arg, FALSE, $name)) {
is_callable(function() {}, TRUE, $implementation);
return ($name === $implementation);
}
}
这将检查传递的参数是否可调用。$name
参数存储可调用的名称。对于闭包,当前是闭包::u invoke
。因为这对于任何闭包/Lambda都是相同的,所以我们可以将传递的参数的名称与任意其他闭包/Lambda进行比较。如果它们相等,则参数必须是闭包/Lambda。在运行时确定可调用名称还有一个额外的好处,即您不必将关于实现细节的假设硬编码到源代码中。传递一个functor将返回FALSE
,因为它不会有相同的可调用名称。由于这不依赖于反射API,因此速度也可能快一点
上述内容可以更优雅地写成
function isClosure($arg) {
$test = function(){};
return $arg instanceof $test;
}
+1尽管需要注意的是,这个是可调用的
对于任何可调用项都将返回TRUE
,而不仅仅是闭包。@Gordon:很对,我在你发布此消息时将其作为对原始问题的注释添加了进来。:-)使用PHP5.3之前的穷人匿名函数create_function
创建的函数怎么样?那么可以是\uu invoke()
d的对象呢?我特别感兴趣的是,您是否可以测试闭包(“…仅当变量是闭包时返回true…”)。我的问题是,为什么要区分函子(或在该点的任何回调)和闭包?在5.3中,你的观点没有什么不同(因为你不能重新绑定任何东西),那么这又有什么关系呢?如果它通过了is_callable()
,那么为什么这还不够呢???从PHP5.4开始,您可以依赖闭包作为闭包:@Gordon感谢您的跟进!我会把它加在上面。很好,我喜欢我的一些反映。很好。这种方法能克服他的“实现细节”问题吗?我想我真的是在问isClosure是否检查类的闭包。@webbiedave-这并不重要,因为我假设对闭包的实现更改将在ReflectionFunction@webbiedave这是一个API调用,因此,您不必担心它的实现细节,只要开发人员更新用于闭包/lambda的类,就可以依靠他们来更新反射API。但既然如此,我想说它以某种不同的方式决定了它(ZEND\u ACC\u CLOSURE
)。@Gordon-差不多,但不完全一样。如何在StdObj、可调用对象和闭包之间进行测试?
method_exists($functorOrClosureOrLambda, '__invoke');
function isClosure($arg)
{
if(is_callable($arg, FALSE, $name)) {
is_callable(function() {}, TRUE, $implementation);
return ($name === $implementation);
}
}
function isClosure($arg) {
$test = function(){};
return $arg instanceof $test;
}