不允许序列化'Closure'

时间:2014-03-16 07:43:55

标签: php exception closures amqp

我的代码中有一个自定义的异常处理程序(曾经正常工作),直到我昨天突然看到这个错误:

PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in /raid0/nginx/www/voiceportal/lib/logutils.php:34 Stack trace:
#0 /raid0/nginx/www/voiceportal/lib/logutils.php(34): serialize(Array)
#1 [internal function]: custom_exception_handler(Object(AMQPConnectionException))
#2 {main}

我读到如果尝试序列化匿名函数可能会导致这种情况,但这就是我犯错的原因:

//logutils.php
function custom_exception_handler($exception) {
   $trace_id = uniqid();
   $trace = serialize(array('trace_id' => $trace_id, 'trace' => $exception->getTrace()));
   ...
}

不确定它是否是由于尝试序列化getTrace()引起的,但如果我没记错的话,它过去就会工作。

最初的例外是(如跟踪中所示)AMQPConnectionException

我想了解导致'Serialization of Closure not allowed'例外的原因。

谢谢!

3 个答案:

答案 0 :(得分:2)

PHP's backtrace structure包括对在堆栈的每个级别调用其方法的对象的引用。当它尝试序列化跟踪时,任何引用闭包的对象(或引用闭包等的引用对象)都将阻止序列化。

在您的情况下,您可以将跟踪重新转换为稍微不那么描述性的形式,或者查找哪些对象包含闭包,并将闭包重新打包为__invoke个实例,或者在通过实现Serializable进行序列化时跳过它们,as described here。您在此处的选择取决于您在跟踪中所做的工作。如果仅仅是为了对出现问题的人类可读描述,请考虑使用getTraceAsString()方法而不是getTrace()

答案 1 :(得分:1)

我编写了一个允许任何Exception序列化的函数。这是通过展平回溯中的复杂值来完成的。

来源:

https://gist.github.com/Thinkscape/805ba8b91cdce6bcaf7c

用法:

//logutils.php
function custom_exception_handler($exception) {
   flattenExceptionBacktrace($exception); // <---- ADD THIS
   $trace_id = uniqid();
   $trace = serialize(array('trace_id' => $trace_id, 'trace' => $exception->getTrace()));
   ...
}

答案 2 :(得分:0)

我知道这是一个老话题,但我想推荐自己的library to serializing stack traces。 Object $ stackTrace可以包含值,可以序列化。未序列化的对象将仅包含自定义的变量转储(@see interface)。