PHP, Sessions, __sleep, and Exceptions

Posted by Justin Carmony on March 23rd, 2012

Today I ran into a problem where my PHP Application would throw this fatal error:

Fatal error: Exception thrown without a stack frame in Unknown on line 0

Which is so much fun, because it doesn’t have a line number, so I had no direction as to what exactly was causing the problem. Some quick googling came up with this website stating the following error:

Most often, the error will appear if you use an exception handler combined with an error reporting to exception handler by converting it to an ErrorException, then there a suddenly a whole new magnitude of ways to throw errors within the exception handle, especially if E_NOTICE, E_STRICT and/or E_WARNING errors are converted. This form most often occurs when you use variables without first initializing them. This error may be preventable by wrapping the exception handler within a try/catch block.

A second form of this error occurs when you attempt to throw an exception in a destructor. This is well documented in the PHP manual, but this can still be triggered if you accidentally throw an exception:

Manually - calling “throw new Exception(‘hello world’)’ in a destructor

Implicitly - calling a function that throws an exception (e.g. calling function foo() which throws an exception)

Error handler (ErrorException) - instating a user-defined function as an error handler which throws an ErrorException (which is still an error)

The problem was that the code I was working with wasn’t using a registered exception handler, nor a destructor. So I went through the controller I was working with and commented out each line, and one by one brought each line back. After a few minutes I found the problem: I had a class that would save itself to the Session, and that class also had a sleep method which is invoked on serialization (see PHP manual). Because I hadn’t manually closed my php session with session_write_close() (PHP Manual), PHP would close the session when cleaning up & closing the request, which is executed outside of the stack. My sleep() function had an error and would throw an exception, leading to the Fatal Error.

It was a little tricky to track down, but made complete sense once I found it.

About Justin Carmony

Justin is the Director of Engineering for Deseret Digital Media, President of the Utah PHP Usergroup, and member of the Utah Open Source Foundation which organizes the OpenWest Conference. Justin loves just about anything with web technologies from PHP, JavaScript, Node.js, Salt, and managing engineering teams.

Learn More