Exception Handling in PHP
To be honest, we should incorporate error checking and management logic into our scripts to defend our website and ensure the scripts are running properly. Validating data before using it is one of the simplest ways to avoid errors from occurring. For example, in our login scripts, we ensure that the user name and password are entered correctly.
Even if we have validated all of the results, there are always errors that we can not anticipate or avoid. For example, suppose we need data from a database in our script but the database server is unavailable at the time. In such a scenario, the mechanism responsible for having the data could actually return null (i.e. no data). However, this is not the safest solution since there are other factors that may cause the data to be unavailable, such as the user id and password used to access the database being invalid.
To deal with these error cases, the concept of exception is used in PHP (which is pretty much the same as in other programming languages).
What is an Exception?
You can think of an exception as an “object” that represents the error that could happen.
For those who are new to computer programming, an “object” is different from a variable (or array) in the sense that it can contain both variables (which we refer to as the object’s properties) and functions that we can execute (which we refer to these functions as methods).
Exception handling is used to change the normal flow of the code execution if a specified error (exceptional) condition occurs. This condition is called an exception.
This is what normally happens when an exception is triggered:
- The current code state is saved
- The code execution will switch to a predefined (custom) exception handler function
- Depending on the situation, the handler may then resume the execution from the saved code state, terminate the script execution or continue the script from a different location in the code
We will show different error handling methods:
- Basic use of Exceptions
- Creating a custom exception handler
- Multiple exceptions
- Re-throwing an exception
- Setting a top level exception handler
Note: Exceptions should only be used with error conditions, and should not be used to jump to another place in the code at a specified point.
Why Exception Handling Is Handy
In a perfect world, your program would run like a well-oiled machine, devoid of both internal and user-initiated errors that disrupt the flow of execution. However, programming, like the real world, remains anything but an idyllic dream, and unforeseen events that disrupt the ordinary chain of events happen all the time. In programmers’ lingo, these unexpected events are known as exceptions. Some programming languages have the capability to react gracefully to an exception by locating a code block that can handle the error. This is referred to as throwing the exception. In turn, the error-handling code takes ownership of the exception, or catches it. The advantages of such a strategy are many.
For starters, exception handling essentially brings order to the error-management process through the use of a generalized strategy for not only identifying and reporting application errors, but also specifying what the program should do once an error is encountered. Furthermore, exception-handling syntax promotes the separation of error handlers from the general application logic, resulting in a considerably more organized, readable code. Most languages that implement exception handling abstract the process into four steps:
- The application attempts something.
- If the attempt fails, the exception-handling feature throws an exception.
- The assigned handler catches the exception and performs any necessary tasks.
- The exception-handling feature cleans up any resources consumed during the attempt.
Almost all languages have borrowed from the C++ language’s handler syntax, known as try / catch . Here’s a simple pseudo code example:
try {
perform some task
if something goes wrong
throw exception(“Something bad happened”)
// Catch the thrown exception
} catch(exception) {
output the exception message
}
You can also set up multiple handler blocks, which allows you to account for a variety of errors. You can accomplish this either by using various predefined handlers or by extending one of the predefined handlers, essentially creating your own custom handler. PHP currently only offers a single handler, exception . However, that handler can be extended if necessary. It’s likely that additional default handlers will be made available in future releases. For the purposes of illustration, let’s build on the previous pseudo code example, using contrived handler classes to manage I/O and division-related errors:
try {
perform some task
if something goes wrong
throw IOexception(“Could not open file.”)
if something else goes wrong
throw Numberexception(“Division by zero not allowed.”)
// Catch IOexception
} catch(IOexception) {
output the IOexception message
}
// Catch Numberexception
} catch(Numberexception) {
output the Numberexception message
}
If you’re new to exceptions, such a syntactical error-handling standard seems like a breath of fresh air. The next section applies these concepts to PHP by introducing and demonstrating the variety of new exception-handling procedures made available in version 5.
Basic Use of PHP Exceptions
When an exception is thrown, the code following it will not be executed, and PHP will try to find the matching “catch” block.
If an exception is not caught, a fatal error will be issued with an “Uncaught Exception” message.
Lets try to throw an exception without catching it:
<?php
//create function with an exception
function checkNum($number)
{
if($number>1)
{
throw new Exception("Value must be 1 or below");
}
return true;
}//trigger exception
checkNum(2);
?>
The code above will get an error like this:
Fatal error: Uncaught exception ‘Exception’ |
Try, throw and catch
To avoid the error from the example above, we need to create the proper code to handle an exception.
Proper exception code should include:
- Try – A function using an exception should be in a “try” block. If the exception does not trigger, the code will continue as normal. However if the exception triggers, an exception is “thrown”
- Throw – This is how you trigger an exception. Each “throw” must have at least one “catch”
- Catch – A “catch” block retrieves an exception and creates an object containing the exception information
Lets try to trigger an exception with valid code:
<?php
//create function with an exception
function checkNum($number)
{
if($number>1)
{
throw new Exception("Value must be 1 or below");
}
return true;
}//trigger exception in a "try" block
try
{
checkNum(2);
//If the exception is thrown, this text will not be shown
echo 'If you see this, the number is 1 or below';
}//catch exception
catch(Exception $e)
{
echo 'Message: ' .$e->getMessage();
}
?>
The code above will get an error like this:
Message: Value must be 1 or below |
Example explained:
The code above throws an exception and catches it:
- The checkNum() function is created. It checks if a number is greater than 1. If it is, an exception is thrown
- The checkNum() function is called in a “try” block
- The exception within the checkNum() function is thrown
- The “catch” block retrives the exception and creates an object ($e) containing the exception information
- The error message from the exception is echoed by calling $e->getMessage() from the exception object
However, one way to get around the “every throw must have a catch” rule is to set a top level exception handler to handle errors that slip through.
Creating a Custom PHP Exception Class
Creating a custom exception handler is quite simple. We simply created a special class with functions that can be called when an exception occurs in PHP. The class must be an extension of the exception class.
The custom exception class inherits the properties from PHP’s exception class and you can add custom functions to it.
Lets create an exception class:
<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
return $errorMsg;
}
}$email = "someone@example…com";try
{
//check if
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
//throw exception if email is not valid
throw new customException($email);
}
}catch (customException $e)
{
//display custom message
echo $e->errorMessage();
}
?>
The new class is a copy of the old exception class with the addition of the errorMessage () function. Since it is a copy of the old class, and it inherits the properties and methods from the old class, we can use the exception class methods like getLine () and getFile () and getMessage ().
Example explained:
The code above throws an exception and catches it with a custom exception class:
- The customException() class is created as an extension of the old exception class. This way it inherits all methods and properties from the old exception class
- The errorMessage() function is created. This function returns an error message if an e-mail address is invalid
- The $email variable is set to a string that is not a valid e-mail address
- The “try” block is executed and an exception is thrown since the e-mail address is invalid
- The “catch” block catches the exception and displays the error message
Multiple PHP Exceptions
It is possible for a script to use multiple exceptions to check for multiple conditions.
It is possible to use several if..else blocks, a switch, or nest multiple exceptions. These exceptions can use different exception classes and return different error messages:
<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = 'Error on line '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b> is not a valid E-Mail address';
return $errorMsg;
}
}$email = "someone@example.com";try
{
//check if
if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
//throw exception if email is not valid
throw new customException($email);
}
//check for "example" in mail address
if(strpos($email, "example") !== FALSE)
{
throw new Exception("$email is an example e-mail");
}
}catch (customException $e)
{
echo $e->errorMessage();
}catch(Exception $e)
{
echo $e->getMessage();
}
?>
Example explained:
The code above tests two conditions and throws an exception if any of the conditions are not met:
- The customException() class is created as an extension of the old exception class. This way it inherits all methods and properties from the old exception class
- The errorMessage() function is created. This function returns an error message if an e-mail address is invalid
- The $email variable is set to a string that is a valid e-mail address, but contains the string “example”
- The “try” block is executed and an exception is not thrown on the first condition
- The second condition triggers an exception since the e-mail contains the string “example”
- The “catch” block catches the exception and displays the correct error message
If the exception thrown were of the class customException and there were no customException catch, only the base exception catch, the exception would be handled there.
Re-throwing PHP Exceptions
Sometimes, when an exception is thrown, you may wish to handle it differently than the standard way. It is possible to throw an exception a second time within a “catch” block.
A script should hide system errors from users. System errors may be important for the coder, but are of no interest to the user. To make things easier for the user, you can re-throw the exception with a user-friendly message:
<?php
class customException extends Exception
{
public function errorMessage()
{
//error message
$errorMsg = $this->getMessage().' is not a valid E-Mail address.';
return $errorMsg;
}
}$email = "someone@example.com";try
{
try
{
//check for "example" in mail address
if(strpos($email, "example") !== FALSE)
{
//throw exception if email is not valid
throw new Exception($email);
}
}
catch(Exception $e)
{
//re-throw exception
throw new customException($email);
}
}catch (customException $e)
{
//display custom message
echo $e->errorMessage();
}
?>
Example explained:
The code above tests if the email-address contains the string “example” in it. If it does, the exception is re-thrown:
- The customException () class was created as an extension of the old exception class. This way, it inherits all methods and properties from the old exception class.
- The errorMessage () function is created. This function returns an error message if an e-mail address is invalid.
- The $email variable is set to a string that is a valid e-mail address, but contains the string “example”.
- The “try” block contains another “try” block to make it possible to re-throw the exception.
- The exception is triggered since the e-mail contains the string “example”.
- The “catch” block catches the exception and re-throws a “customException”
- The “customException” is caught and displays an error message.
If the exception is not caught in its current “try” block, it will search for a catch block on “higher levels”.
Set a Top Level Exception Handler
The set_exception_handler() function sets a user-defined function to handle all uncaught exceptions.
<?php
function myException($exception)
{
echo "<b>Exception:</b> " , $exception->getMessage();
}set_exception_handler('myException');throw new Exception('Uncaught Exception occurred');
?>
The output of the code above should be something like this:
Exception: Uncaught Exception occurred |
In the code above there was no “catch” block. Instead, the top level exception handler triggered. This function should be used to catch uncaught exceptions.
Rules for php exceptions
- Code may be surrounded in a try block, to help catch potential exceptions
- Each try block or “throw” must have at least one corresponding catch block
- Multiple catch blocks can be used to catch different classes of exceptions
- Exceptions can be thrown (or re-thrown) in a catch block within a try block
A simple rule: If you throw something, you have to catch it.