FAQ
Hi All,

A while ago, I discovered the awkward fact that PHP exceptions can only
sometimes be serialized, because they contain a stack trace which might
involve non-serializable objects.

In my case, one of the function calls in the trace happened to have been
passed a SimpleXMLElement as an argument; similarly, anything passed a
closure will render the trace unserializable. A quick example is here:
http://codepad.viper-7.com/A6U91A

When I mentioned this in SO chat, the general response was "yeah, don't
do that". Which leads me to my first suggestion: (1) the base Exception
class should *always* prevent serialization, in the same way that it
always prevents cloning. This would prevent people like me writing code
to do it, and only finding out later that it is a Bad Idea.

(As background, my use case was some code that used serialized objects
to pass call-backs and their responses between processes in a kind of
"fake threading"; I wanted exceptions to bubble up to the parent
"thread" just as though the callback had been executed locally.)

On the other hand, most of the Exception, including its trace *can*
actually be serialized - an actual call to a closure is simply given the
function name '{closure}', and the object on which a method was called
is stored only as its class name, like debug_backtrace without
DEBUG_BACKTRACE_PROVIDE_OBJECT. The only part that is at risk of causing
serialization errors is the 'args' element in each stack trace entry.

This leads to two further possibilities:

(2) Don't capture arguments in the trace of an exception, similar to
debug_backtrace with DEBUG_BACKTRACE_IGNORE_ARGS set. This would
technically be a BC break, but I'm not sure how much real code would
care. It's impossible to reconstruct details of the calls fully without
the PROVIDE_OBJECT behaviour anyway.

This would also have the advantage of making destructors fire more
predictably - at the moment, an exception can bubble past a block of
code with a deliberately scoped object (e.g. an RAII-style lock token),
and if that object happens to be an argument within the Exception's
trace, it survives until the Exception itself is destructed, because it
has a reference inside the Exception's trace. Again, arguably you
shouldn't be relying on this or keeping Exception objects around for
long anyway, but it's kind of unexpected behaviour.

Alternatively (3), serializing an Exception could discard the 'args'
keys in the trace, but retain the rest of the information; or (4) a
method could be made to explicitly discard these and mark the object
safe for serialization. This lets code that relies on that informaion
continue unchanged, while allowing the information needed for most use
cases to be serialized as safely as any other object.

It seems to me that any one of these options would be better than the
current unpredictable behaviour, but I'm more than willing for someone
to point out the flaw in my reasoning.

Regards,
--
Rowan Collins
[IMSoP]

Search Discussions

  • Tim Starling at Oct 7, 2013 at 11:03 pm

    On 08/10/13 09:01, Rowan Collins wrote:
    (2) Don't capture arguments in the trace of an exception, similar to
    debug_backtrace with DEBUG_BACKTRACE_IGNORE_ARGS set. This would
    technically be a BC break, but I'm not sure how much real code would
    care. It's impossible to reconstruct details of the calls fully
    without the PROVIDE_OBJECT behaviour anyway.

    This would also have the advantage of making destructors fire more
    predictably - at the moment, an exception can bubble past a block of
    code with a deliberately scoped object (e.g. an RAII-style lock
    token), and if that object happens to be an argument within the
    Exception's trace, it survives until the Exception itself is
    destructed, because it has a reference inside the Exception's trace.
    Again, arguably you shouldn't be relying on this or keeping
    Exception objects around for long anyway, but it's kind of
    unexpected behaviour.
    Is it possible to make the trace options be overridable by the
    Exception subclass? That would provide a migration path for any code
    that did rely on the args being available. And I think our app could
    benefit from having closure objects available for logging, especially
    if it is possible to get line numbers.

    -- Tim Starling
  • Rowan Collins at Oct 8, 2013 at 8:26 am

    Tim Starling wrote (on 08/10/2013):
    Is it possible to make the trace options be overridable by the
    Exception subclass? That would provide a migration path for any code
    that did rely on the args being available. And I think our app could
    benefit from having closure objects available for logging, especially
    if it is possible to get line numbers.

    -- Tim Starling
    The problem with that is that you can't control what exceptions are
    thrown by third-party libraries (or even some of the newer core
    extensions), or force them to inherit from your base. If they turn off
    the argument capture, the information will already be unavailable when
    you catch the exception, and if they turn it on, you will still need a
    function to strip it after the fact.

    Obviously you can discard the third-party exception and throw your own,
    but normally you would chain yours onto it, retaining whatever
    information it originally contained.

    --
    Rowan Collins
    [IMSoP]

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedOct 7, '13 at 10:01p
activeOct 8, '13 at 8:26a
posts3
users2
websitephp.net

2 users in discussion

Rowan Collins: 2 posts Tim Starling: 1 post

People

Translate

site design / logo © 2022 Grokbase