Search

Misconceptions about Exceptions

Thursday, August 2. 2007

I was surprised the other day when someone came into ##php on freenode wanted a strange feature when he hit a wall designing his app with exceptions. He wanted something like the following:

//NOTE THIS IS NOT POSSIBLE, IT'S BULLCRAP!!
try {
  throw new Exception("throw an exception");
} catch (Exception $e) {
  //do something with a thrown exception.
} else {
  //do something if there wasn't an exception thrown.
}

That's right, he wanted an 'else' for a try/catch block. My mind was blown, surely he was using exceptions wrongly. After I did some inquiring on why he wanted such a ridiculous feature, I found out he was indeed misusing exceptions. He was using exceptions to control his code execution flow. Using them to drive his application by recoverable errors. He was quite defensive about it too! I decided if there weren't enough blog articles about correct exception usage, there needed to be one more...

This tutorial isn't specific to PHP, It applies to all languages that support exceptions. Error checking is very important in any language. You should be checking for any possible place where an error can occur.

 
$db = new my_db('host','user','pass','db');
if($db->connect_error()){
  die("Error Connected to the Database");
}
$stmt = $db->prepare("SELECT * FROM table WHERE field = ?");
if($db->error()){
  die("Could not prepare query");
}
$stmt->bind_param(1,'value');
$stmt->execute();
if($db->error()){
  die("Could not execute query");
}
 

With exceptions this becomes a lot cleaner. The error checking can all be moved to one place.

 
try {
  $db = new my_db('host','user','pass','db');
  $stmt = $db->prepare("SELECT * FROM table WHERE field = ?");
  $stmt->bind_param(1,'value');
  $stmt->execute();
} catch (Exception $e) {
  die($e->getMessage());
}
 

Exceptions are great. But they're meant to track one kind of error only: Exceptional Errors. Exceptional errors are non-recoverable. Exceptional errors are things that are unexpected. Exceptional errors should not have happened in any normal sense. If you remove all Exception handling in your code, the code should still run (that is if nothing exceptional happened.)

Here are some examples where an exception is not warranted:

  • User enters an incorrect password, you should expect this
  • A user enters alpha characters in a phone number field that should only contain digits, WRONG, but you should expect this behavior
  • Checking that a file exists that you have no idea if it should exist or not.
  • A Search returns no results.

Examples of where exceptions may be warranted:

  • A database connection fails that should be able to connect.
  • A SQL query cannot execute because it is malformed.
  • Checking that a file exists that should be there.
  • A Parser cannot parse because the data is malformed.
  • Checking for existence of required properties in a class that should have been set before a method was run.

Why this distinction of when to use exceptions? The biggest reason is that exceptions moves the code execution to a catch statement much like goto moves code execution to a different part of the program, and can create spaghetti code if used incorrectly. A normal day to day catch statement should show a friendly error to the user, log or show the exception, and halt the execution flow.

I hope this article helps readers understand when to use exceptions, and if it can prevent just one person from designing their code like the user in the first paragraph, it did it's job.

References:
Hunt, Andrew and Thomas, David The Pragmatic Programmer Addison-Wesley, Feb 2006.


Posted by Chad Emrys Minick in PHP, Programming at 11:09 PM | Comments (2)
delicious logo digg logo technorati logo furl logo stumble upon logo feed logo

Comments

In reply to comment #8
Right, thats not what they were trying to achieve. It's been awhile since I talked to this fellow. He actually wanted to jump to different parts of code for non-exceptional errors like validation.

The Zend_Controller catch was meant to allow for a common graceful death from uncaught exceptions, not to find a way to continue the application's normal flow.
#9 Posted By: Chad Minick | October 26, 2007 11:13 AM | reply
Using Zend_Controller it is common for Exceptions to bubble all the way up and be handled at the bootstrap (if not handled by a plugin beforehand).

When you have to catch a lot of different exceptions at the same place it might be a good idea to use conditional style code to determine the type of error and deal with it accordingly.

Using PHP exceptions you would do something like:

try {
//some code here
//that runs the application
//and may return one or more types of
//exception
} catch (Zend_Database_Exception $e) {
//special case for handling a database exception
} catch (Zend_Exception $e) {
//our framework is throwing exceptions
} catch (Exception $e) {
//if we haven't already
//caught the exception
//in a special case
//then we can handle it here
//generically
}

I think that is what they were trying to achieve.
#8 Posted By: Daniel Skinner | October 22, 2007 10:21 AM | reply

Add Comment

  E-Mail address will not be displayed.
Cookies must be enabled to post a comment
goawai
 
 
 *Required Field