Still returning false whenever a function in your program fails? In this article, we’ll learn about PHP exceptions, and how you can use them to soup up your application’s error handling.
Introduction
What are exceptions?
Exceptions are special conditions, usually errors, that can occur or be explicitly made by a program. They connote that something entirely different from what was expected has occurred. In most cases, the situation requires that a special instruction set be done in order to mitigate a catastrophic system failure.
How do we use exceptions?
Exceptions can be thrown
and caught
. When an exception is thrown, it means that something out of the ordinary has happened, and it will require another function to do something else. Catching
an exception is the function telling the rest of the program, “Hey, I can handle this exception, let me at it!”
Exceptions can be explained by using the analogy of a baseball game.
- The pitcher (Bowser) throws a baseball to the catcher.
- The batter (Mario) tries to hit the ball. If he’s not able to do it, he gets a strike. If he’s able to do it, a fielder (either Donkey Kong or Waluigi) has to catch it.
- If Donkey Kong catches the ball, he then has two choices: if he’s not close enough, he can throw it to another fielder; or if he’s close enough, he can throw it to a baseman and tag Mario to get an out.
In exceptions, the pitcher throwing a baseball to the catcher is like a function running normally.
But when the batter hits the ball, something “exceptional”
happens, and certain routines need to be done.
A fielder catching the baseball is like a try-catch function
getting the exception. This try-catch function can now either handle the exception, or throw it for another try-catch function to handle. Whichever try-catch function can handle the exception is the one that finally does something.
Using PHP Exceptions
It’s really simple to implement exceptions in PHP. Since exceptions are part of the Standard PHP Library or SPL, they’re part of PHP core as long as you’re running PHP 5 and above. Exceptions are already there, just longing and waiting to be used.
Exceptions are instantiated the same way as objects:
$exception = new Exception(); throw $exception;
Much like objects, they also have methods that can be called. These methods make it easier for a try-catch function to react to exceptions. For example, the getMessage()
function will let you get an exception’s error message, which you can then log or show on the browser.
Here’s a list of an exception’s methods:
getMessage()
– gets the exception’s messagegetCode()
– returns a numerical code that represents the exceptiongetFile()
– returns the file where the exception was throwngetLine()
– returns the line number in the file where the exception was throwngetTrace()
– returns the an array of the backtrace() before the exception was throwngetPrevious()
– returns the exception thrown before the current one, if anygetTraceAsString()
– returns the backtrace() of an exception as a string instead of an array__toString()
– returns the whole exception as a string. Isoverrideable
.
To better illustrate these methods, let’s create a User
class that does basic user record management:
<?php class User { protected $_user_id; protected $_user_email; protected $_user_password; public function __construct($user_id) { $user_record = self::_getUserRecord($user_id); $this->_user_id = $user_record['id']; $this->_user_email = $user_record['email']; $this->_user_password = $user_record['password']; } //we'll fill these in later public function __get($value) {} public function __set($name, $value) {} private static function _getUserRecord($user_id) { //For this tutorial, we'll use a mock-up record to represent retrieving the record //from the database and returning the data $user_record = array(); switch($user_id) { case 1: $user_record['id'] = 1; $user_record['email'] = 'nikko@example.com'; $user_record['password'] = 'i like croissants'; break; case 2: $user_record['id'] = 2; $user_record['email'] = 'john@example.com'; $user_record['password'] = 'me too!'; break; case 'error': //simulates an unknown exception from whatever SQL library is being used: throw new Exception('An error from the SQL library!'); break; } return $user_record; } } ?>
In this example, there are several places where something exceptional
could happen. For starters, the $user_id input in our _getUserRecord()
function should be an integer. In the event that it’s not, we should throw an exception:
... ... ... private static function _getUserRecord($user_id) { $user_id = self::_validateUserId($user_id); ... ... ... } private static function _validateUserId($user_id) { if( !is_numeric($user_id) && $user_id != 'error' ) { throw new Exception('Whoa! I think there\'s something wrong with the user id'); } return $user_id; }
Let’s try it out by instantiating our User class with an invalid parameter:
//First try getting our user numero uno $user = new User(1); //Then, let's try to get the exception $user2 = new User('not numeric');
You should get an error like this:

Uncaught exception error message
Now, let’s have Donkey Kong catch this exception.
try { //First try getting our user numero uno $user = new User(1); //Then, let's try to get the exception $user2 = new User('not numeric'); } catch( Exception $e ) { echo "Donkey Kong has caught an exception: {$e->getMessage()}"; }
Let’s run it again, this time with our try-catch function:

Thanks Donkey Kong!
As you can see, with Donkey Kong catching our exceptions, we were able to suppress the awful error messages thrown by PHP when an exception is uncaught.
One thing to note here is that when an exception is thrown, it only stops when a try-catch function is able to catch it. Otherwise, it will remain uncaught, keep climbing up the trace of the function call, and be displayed as an error on the browser. In our current example, let’s trace where our exception gets thrown:
- Create a new
User
object on the$user2 = new User('not numeric');
line - Run the
__construct()
function of theUser
class - Go to the
_getUserRecord()
function of theUser
class - Validate the
$user_id
using the_validateUserId
function - If the
$user_id
is not numeric, throw a new Exception object
We can also run the getTraceAsString()
function to get the trace of the exception, which will give us the exact same thing:
... ... } catch( Exception $e ) { echo "Donkey Kong has caught an exception: {$e->getMessage()}"; echo '<pre>'; echo $e->getTraceAsString(); echo '</pre>'; }

getTraceAsString()
results
As you can see, even if the exception is thrown deep inside the trace of $user2 = new User('not numeric')
, it keeps climbing up until it gets caught in the try-catch block on the top-most level.
Now, let’s construct our exception to use a code. Associating a code number with an exception is a good way of hiding the error from the client. By default, the code number of an exception is 0
, but we can override this whenever we create a new exception:
... ... ... if( !is_numeric($user_id) ) { throw new Exception('Whoa! I think there\'s something wrong with the user id', UserErrors::INVALIDID); } ... ... ...
Don’t forget to create our UserErrors class:
class UserErrors { const INVALIDID = 10001; const INVALIDEMAIL = 10002; const INVALIDPW = 10003; const DOESNOTEXIST = 10004; const NOTASETTING = 10005; const UNEXPECTEDERROR = 10006; public static function getErrorMessage($code) { switch($code) { case self::INVALIDID: return 'Whoa! I think there\'s something wrong with the user id'; break; case self::INVALIDEMAIL: return 'The email is invalid!'; break; case self::INVALIDPW: return 'The password is shorter than 4 characters!'; break; case self::DOESNOTEXIST: return 'That user does not exist!'; break; case self::NOTASETTING: return 'That setting does not exist!'; break; case self::UNEXPECTEDERROR: default: return 'An unexpected error has occurred'; break; } } }
We can then modify our exception handler to display the exception code instead of displaying the message:
... ... } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}"; }
It should result in this:

Now, let’s use all the other methods of an exception by trying to log the exception. First off, let’s create our Logger
class:
class Logger { public static function newMessage( Exception $exception, $clear = false, $error_file = 'exceptions_log.html' ) { $message = $exception->getMessage(); $code = $exception->getCode(); $file = $exception->getFile(); $line = $exception->getLine(); $trace = $exception->getTraceAsString(); $date = date('M d, Y h:iA'); $log_message = "<h3>Exception information:</h3> <p> <strong>Date:</strong> {$date} </p> <p> <strong>Message:</strong> {$message} </p> <p> <strong>Code:</strong> {$code} </p> <p> <strong>File:</strong> {$file} </p> <p> <strong>Line:</strong> {$line} </p> <h3>Stack trace:</h3> <pre>{$trace} </pre> <br /> <hr /><br /><br />"; if( is_file($error_file) === false ) { file_put_contents($error_file, ''); } if( $clear ) { $content = ''; } else { $content = file_get_contents($error_file); } file_put_contents($error_file, $log_message . $content); } }
We’ll have to modify our exception handler to use the Logger
class:
... ... } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}"; Logger::newMessage($e); }
Now, when we run our program again, it should just display the exception code. We can then open the exceptions_log.html
file and we’ll see the log of exceptions we’re getting:

Congratulations!
You now have working knowledge on how to implement basic PHP Exceptions. Now, let’s move on to more advanced stuff!
Extending Exceptions
Even at their most basic level, exceptions are already an essential tool for error handling in applications. By extending exceptions
, however, we can create our own customized exceptions and take our application’s exception handling to the next level.

The next level is THIS much fun.
To create a custom exception, we’ll need to create our own exception class, extending the Exception
class. Let’s create a custom UserException
for our user class:
class UserException extends Exception { public function __construct($error_code) { parent::__construct(UserErrors::getErrorMessage($error_code), $error_code); Logger::newMessage($this); } }
As you can see, we overrode the __construct
function to implement our own constructor. Since we extended the Exception
object, we’re still able to use the default Exception constructor by using the parent
keyword. By doing this, we can skip providing an error message every time we throw an exception, and just provide an exception code. We can also skip having to log it ourselves, since the custom constructor is set up to automatically log the exception.
Let’s update our code to use the new UserException class:
private static function _validateUserId($user_id) { if( !is_numeric($user_id) && $user_id != 'error' ) { throw new UserException(UserErrors::INVALIDID); } return $user_id; }
Since the exception already automatically logs itself, we can skip logging it in our try-catch block:
... ... } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}"; //Logger::newMessage($e); }
Let’s also update the other places in our User
class where we can expect exceptions.
User
class:
... ... ... public function __get($value) { $value = "_{$value}"; if( !isset($this->$value) ) { throw new UserException(UserErrors::NOTASETTING); } return $this->$value; } public function __set($name, $value) { switch($name) { case 'user_id': $user_id = self::_validateUserId($value); $this->_user_id = $user_id; break; case 'user_email': $user_email = self::_validateUserEmail($value); $this->_user_email = $user_email; break; case 'user_password': $user_password = self::_validateUserPassword($value); $this->_user_password = $user_password; break; default: throw new UserException(UserErrors::NOTASETTING); break; } return true; } private static function _getUserRecord($user_id) { ... ... ... switch($user_id) { ... ... ... default: throw new UserException(UserErrors::DOESNOTEXIST); break; } }
Now let’s try triggering these exceptions:
$user = new User(1); try { $user->user_email = 'invalid email'; } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}<br />"; } try { echo $user->setting_that_doesnt_exist; } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}<br />"; } try { //user id that doesn't exist $user = new User(3); } catch( Exception $e ) { echo "Donkey Kong has caught an exception with code: #{$e->getCode()}<br />"; }
We should get something like this:

You’re probably wondering — besides custom constructors, what benefits can we get from custom exceptions? It would be relatively simple to just use the default Exception class. But by using a custom exception, we can:
- Override the
__construct
function and implement our own - Organize our exceptions by the type of object they are
- And the best one of all: Use multiple catch blocks and catch different kinds of exceptions depending on type!
Multiple Catch Blocks
By using multiple catch blocks, we are able to catch specific types of exceptions. This can be useful since we can indicate what to do when different kinds of exceptions occur. Currently, our try-catch functions catch the regular Exception
type exceptions — this allows us to provide a fail-safe catch block for exceptions of types that have not been planned for.
With that in mind, let’s create a try-catch function that will catch our custom exception, UserException
, and do something different about it. Let’s also use another catch block to make sure that any other unexpected exceptions that are thrown will still be caught.
try { $user = new User(1); $user->user_password = '123'; } catch( UserException $e ) { echo "Donkey Kong has caught a User Exception with code: #{$e->getCode()}<br />"; } catch( Exception $e ) { echo "Donkey Kong has caught a Exception with code: #{$e->getCode()}<br />"; } try { //when we use 'error' as the argument, the User class will simulate an //unexpected exception from the SQL library $user = new User('error'); } catch( UserException $e ) { echo "Donkey Kong has caught a User Exception with code: #{$e->getCode()}<br />"; } catch( Exception $e ) { echo "Donkey Kong has caught a Exception with code: #{$e->getCode()}<br />"; }
We should see the following output:

We can clearly see that the UserException and the regular Exception were handled differently, since they have different messages. It may not seem useful right now, but imagine being able to log only certain exceptions, or even create a custom exception called DisplayableException
, which we can set so that they’re the only ones that users will be able to see.
Conclusion
With the power of PHP exceptions
, we can simply and easily handle different kinds of errors. Hopefully, with the help of this tutorial, you’ll be able to build from our simple example and create an even more effective way of handling your application’s errors through PHP exceptions.
Do you use exceptions in your applications? What kind of exceptions do you use? Let me know in the comments!