Introduction to PHP Exceptions

I gave a talk on Dealing with Errors at the PHP Unconference 2011 in Manchester, and notes were requested. So these posts cover the content of the talk, and more besides. This post covers Exceptions.

PHP Exceptions are a object-orientated way of triggering errors and dealing with them.

try {
   throw new Exception();
   print "This line is never run";
} catch (Exception $e) {
   print "error";
}

You can create a new exception object, and throw it. When thrown PHP will work back up the code stack looking for a catch block that can handle it. You can have as much code as you want in a try or catch block.

Because exceptions are just objects, you can extend them

class MyError extends Exception {}
try {
   throw new MyError();
} catch (MyError $e) {
   print "error";
} catch (Exception $e) {
   print "error";
}

Note you can have multiple catch blocks and the appropriate catch block will be used. Inheritance works; so any error that extends the Exception class will be caught by the catch(Exception $e) block.

PHP has a number of built in predefined exception classes you can use.

You can also re-throw an exception:

try {
   throw new Exception();
} catch (Exception $e) {
   throw $e;
}

So in your catch block you can run some code (maybe clean up a resource, like close a file you have opened and were half way through reading) then re-throw the exception for it to be dealt with by other code.

Any exceptions that aren’t caught will kill your script. You can catch them and do something with them before PHP dies. This example is directly from the set_exception_handler() manual.

function exception_handler($exception) {
   echo "Uncaught exception: " , $exception->getMessage(), "n";
}
$old_exception_handler = set_exception_handler('exception_handler');
throw new Exception('Uncaught Exception');
echo "Not Executedn";

You can only have one exception handler at a time, but you can store the name of the old exception handler and call it yourself in your exception handler – more on this later.

Getting information out of Exceptions

This is easy with the getMessage(), getFile(), getLine() and getTrace() functions.

However note that these don’t give you the place that the error was thrown from but the place the exception was created (contrary to documentation). Seeing as almost all of the time people create and throw the exception on the same line, it’s not a problem and is in fact is a good thing – if you re-throw the exception then the information in it will be from the original problem, not when it was re-thrown. But if you create an exception then pass it around for a bit then watch out for this.

When to use exceptions?

That is a matter of personal choice, but here are some suggestions to get you thinking.

If a function returns a value, or 0 or -1 for an error, that could be a candidate. Especially if there are multiple errors: you may think it’s easy to return -1, -2 and so on but that makes it very easy for a programmer to forget to check for an error state (and they will probably have to refer to the manual all the time). Instead, throw an Exception if there is an error. This is harder to ignore and much more readable.

What if a function returns a failure state that evaluates to the same as a valid state when doing a lazy comparison? intval() returns “The integer value of var on success, or 0 on failure.” Which means that these 3 statements all return the same!

intval('0')
intval('')
intval('oeuoehtu')

If your writing a function for a web-app which has a text field to collect an integer input, you want the 1st to return 0,the 2nd null (to indicate the user did not put anything in), and the last to raise an error or exception.

Handling Errors and Exceptions leaving you puzzled? We work on an open source project to log problems, display a nice message to the user and email developers. We detect duplicates and let you track errors in tickets. Have a look at the ErrorReportingService module in Elastik!

2 thoughts on “Introduction to PHP Exceptions”

  1. hi,

    > …maybe clean up a resource, like close a file you have opened…
    no! you do not want to duplicated code!

    you want to clean up resources:
    – in normal flow (if there is no Exception)
    – in each catch-block (“you can have multiple catch blocks”)

    normally this should be done in “finally” but php has no “finally” yet:
    http://bugs.php.net/bug.php?id=32100

    so php forces you to encapsulate such logic in an object and do the “clean up” in ” __destructor” as described here:
    http://www2.research.att.com/~bs/bs_faq2.html#finally

    if you think this is not suitable, please vote for:
    http://bugs.php.net/bug.php?id=36779

    1. Fair point, you do end up having to duplicate code. Having a finally clause would be good.

      Using __destruct() to clean up resources can be handy, but sometimes it can be a long time after the object goes out of scope before this is called. I believe earlier version of PHP didn’t call it until script shutdown. For web requests this doesn’t matter (they are very short by nature), but for long running processes this may cause problems. Just something to be aware of.

      Maybe I should think of a better example – I just wanted to illustrate that you can re-throw Exceptions 🙂

Comments are closed.