无法破坏活动的lambda函数

时间:2013-01-19 05:40:48

标签: php lambda closures

有人能告诉我在PHP中看到这个错误的最常见原因:

  

无法在...中破坏活动的lambda函数。

我猜测某处有代码试图销毁一个包含对自身引用的闭包,编译器对此感到恼火。

我们经常得到这些比我想要的更多,我想知道我们使用的是什么模式,这可能是造成它的罪魁祸首。

我会附上一个代码段,但错误通常指向的文件不是文件中可能提供提示的行。

3 个答案:

答案 0 :(得分:1)

在php.net上发布了类似的bug。以下是链接。

希望它对你有所帮助。

https://bugs.php.net/bug.php?id=62452

答案 1 :(得分:1)

这样的致命错误会产生如下代码:

set_exception_handler(function ($e) {
        echo "My exception handler";

        restore_exception_handler();

        throw new Exception("Throw this instead.");
});
throw new Exception("An exception");

或者像这样:

function destroy_handler() {
    restore_exception_handler();
}

function update_handler() {
    destroy_handler();
}

set_exception_handler(function ($e) {
        echo "My exception handler";

        update_handler();

        throw new Exception("Throw this instead.");
});
throw new Exception("An exception");

当抛出异常时,执行给set_exception_handler()的回调,并且一旦调用restore_exception_handler(),就会发生致命错误,因为对该闭包的相同引用被销毁(或重新分配)在其自己的范围内(hanskrentel at yahoo dot de发布的链接中的Sameer K示例也是如此)。

从第二个示例可以看出,即使使用嵌套作用域,也会出现相同的情况。这是因为restore_exception_handler会破坏最后设置的异常处理程序,而不是它的副本(它就像重新分配变量或者在你仍在评估将赋予变量的表达式时取消设置它一样)初始值)。

如果你说你的代码中的错误指向另一个文件,我建议你检查你的lambda中的所有调用执行"跳转"在其他文件中的函数和/或方法中,检查是否重新分配或销毁对lambda本身的引用。

答案 2 :(得分:1)

set_exception_handler将返回先前的异常处理程序:

  

返回先前定义的异常处理程序的名称,或者在出错时返回NULL。如果未定义先前的处理程序,则还返回NULL。   php.net: set_exception_handler

<?php

class MyException extends Exception {}

set_exception_handler(function(Exception $e){
    echo "Old handler:".$e->getMessage();
});

$lastHandler = set_exception_handler(function(Exception $e) use (&$lastHandler) {
    if ($e instanceof MyException) {
        echo "New handler:".$e->getMessage();
        return;
    }

    if (is_callable($lastHandler)) {
        return call_user_func_array($lastHandler, [$e]);
    }

    throw $e;
});

触发异常处理程序:

throw new MyException("Exception one", 1);

输出:New handler:Exception one

throw new Exception("Exception two", 1);

输出:Old handler:Exception two