Get your FREE 30 page Developing SOLID Applications guide!

Exceptional PHP: Nesting Exceptions In PHP

Out Of Date Warning

Languages change. Perspectives are different. Ideas move on. This article was published on November 12, 2009 which is more than two years ago. It may be out of date. You should verify that technical information in this article is still current before relying upon it for your own purposes.

In the last two entries we have talked about the concept of layer abstraction: that is, that exceptions should not be allowed to pass out of one layer and into another. So, when an exception is raised in the database layer it should be caught in the controller. But how do we go about making sure that exceptions raised in the database layer are properly recorded and processed, ensuring that we have error logging and don’t simply silence our exceptions?

There are a number of ways to encapsulate one exception within another, or “nest” our exceptions. Let’s discuss the ways.

Nesting Exception Messages
The base Exception class has a built-in __toString() magic method, meaning that we can automatically convert our exceptions into strings. This makes the following possible:


try {
    throw new Exception('Message 1');
} catch (Exception $e) {
    $e = new Exception('Message 2: ' . $e);
} 

try {
	throw $e;
} catch (Exception $e) {
    $e = new Exception('Message 3: ' . $e);
} 

try {
	throw $e;
} catch (Exception $e) {
    throw new Exception('Message 4: ' . $e);
}

We get back the following exception error message:

Exception: Message 4: exception ‘Exception’ with message ‘Message 3: exception ‘Exception’ with message ‘Message 2: exception ‘Exception’ with message ‘Message 1′

The messages are nested, but this does generate some potential issues. First, our exceptions do not have stack traces; the logged stack trace will be the stack trace given in the final exception. Second, the exception message doesn’t contain the exception message codes. However, for simple nested exceptions, this is a good strategy.

Extending Base Exception And Writing Nesting Code
It is possible in PHP to nest exceptions by writing code to do so. For example:

<?php

class MyException extends Exception
{
	protected $priorException;

	public function __construct($message, $code = 0, Exception $previous = null)
	{
		$this->priorException = $previous;
		
		parent::__construct($message, $code);
	}
	
	public function getPrior()
	{
		return $this->priorException;
	}
}

This exception will take a third optional argument of a previous exception, allowing you to nest the exceptions. When preparing to log your exception, you can opt to iterate through any possible previously thrown and nested exceptions, and log any of the data you need.

Using PHP 5.3’s Built-In Nested Exceptions
Anyone that noticed the kludgy way I named the $priorException variable probably wondered why; the reason is that PHP 5.3 introduces nested exceptions as a default part of the PHP base Exception class. While the above code will work, if you are utilizing PHP 5.3, you can pass any previous exception as a third argument (like above), and use the Exception::getPrevious() method to get a previously raised exception.

It would still be wise to develop code that would iterate through the exceptions and log the various data you need; PHP doesn’t incorporate a way to automatically do this.

Summary
You can honor layer abstraction and still ensure that the errors raised are logged and handled appropriately using the various exception nesting techniques above. Ultimately, as PHP improves, so will the nesting options in exceptions.

Write better object oriented PHP today.

Object oriented programming always leaves you with a headache. What if you could master it instead?

Get the book now! »

Chris D wrote at 11/13/2009 3:44 pm:

I just wanted you to know how glad I am to see someone in the PHP-osphere is still creating blog posts that teach something about the language. When I first started with PHP about 5 years ago, Planet PHP was a good source for learning about the language.

Anymore, it’s just a clearing house for for conference announcements