PHP Exception Handling
Exceptions are used to alter the normal flow of a script when a specified error occurs.
What is an Exception
PHP 5 introduces a new object-oriented way of handling errors.
Exception handling is used to change the normal flow of a script when a specified error (exception) condition occurs. This condition is called an exception.
When an exception is triggered, the following usually happens:
- The current code state is saved
- Code execution is switched to a predefined (custom) exception handler function
- Depending on the situation, the handler may resume execution from the saved code state, terminate the script, or continue execution from another location in the code
We will demonstrate different error handling methods:
- Basic usage of exceptions
- Creating a custom exception handler
- Multiple exceptions
- Re-throwing exceptions
- Setting a top-level exception handler
Note: Exceptions should only be used in error conditions, and should not be used to jump to another place in the code at a specified point.
Basic Usage of Exceptions
When an exception is thrown, the code following it will not be executed, and PHP will attempt to find a matching "catch" block.
If an exception is not caught, and no set_exception_handler()
is used to handle it, a fatal error will occur with an "Uncaught Exception" message.
Let's try to throw an exception without catching it:
<?php
// Create a function with exception handling
function checkNum($number)
{
if($number > 1)
{
throw new Exception("Value must be 1 or below");
}
return true;
}
// Trigger exception
checkNum(2);
?>
The above code will produce an error similar to this:
Fatal error: Uncaught exception 'Exception' with message 'Value must be 1 or below' in /www/tutorialpro/test/test.php:7 Stack trace: #0 /www/tutorialpro/test/test.php(13): checkNum(2) #1 {main} thrown in /www/tutorialpro/test/test.php on line 7
Try, Throw, and Catch
To avoid the error from the previous example, we need to create proper code to handle the exception.
Proper exception handling code should include:
- Try - The function using the exception should be in a "try" block. If no exception is triggered, the code will continue as normal. But if an exception is triggered, an exception is thrown.
- Throw - This specifies how to 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.
Let's trigger an exception:
<?php
// Create a function with exception handling
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 an exception is thrown, this text will not be shown
echo 'If this is shown, it means the $number variable is 1 or below';
}
// Catch exception
catch(Exception $e)
{
echo 'Message: ' .$e->getMessage();
}
?>
The above code will produce an error similar to this:
Message: Value must be 1 or below
Example Explained
The above code throws and catches an exception:
- A
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 in the
checkNum()
function is thrown. - The "catch" block catches the exception and creates an object containing the exception information ($e).
- The error message from the exception is output by calling
$e->getMessage()
.
However, to adhere to the principle of "each throw must have a catch," a top-level exception handler can be set to handle uncaught exceptions.
Creating a Custom Exception Class
Creating a custom exception handler is very simple. We simply create 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.
This custom customException
class inherits all properties from the PHP exception
class and can be extended with custom functions.
<?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 = "[email protected]";
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();
}
?>
This new class is a copy of the old exception class, plus the errorMessage() function. Since it is a copy of the old class, it inherits the properties and methods of the old class, and we can use the methods of the exception class, such as getLine(), 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 properties and methods of the old exception class.
The errorMessage() function is created. If the e-mail address is not valid, it returns an error message.
The $email variable is set to an invalid e-mail address string.
The "try" block is executed, and since the e-mail address is not valid, an exception is thrown.
The "catch" block catches the exception and displays the error message.
Multiple Exceptions
Multiple exceptions can be used for a script to check for various conditions.
Multiple if..else blocks, or a switch block, or nested exceptions can be used. 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 = "[email protected]";
try
{
// Check if
if (filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
{
// Throw exception if email is not valid
throw new customException($email);
}
// Check if "example" is in the email 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 for 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 properties and methods of the old exception class.
The errorMessage() function is created. If the e-mail address is not valid, it returns an error message.
Set the $email variable to a string that is a valid email address but contains the string "example". Execute the "try" code block, which will not throw an exception under the first condition. Since the email contains the string "example", the second condition will trigger an exception. The "catch" block will catch the exception and display an appropriate error message. If the customException class throws an exception but does not catch customException, only catching the base exception, handle the exception there. --- ## Re-throwing Exceptions Sometimes, when an exception is thrown, you may want to handle it differently than the standard way. You can re-throw an exception in a "catch" block. Scripts should hide system errors from the user. System errors may be important to programmers, but users are not interested in them. To make it easier for users, you can re-throw an exception with a user-friendly message: ```php <?php class customException extends Exception { public function errorMessage() { // Error message $errorMsg = $this->getMessage().' is not a valid E-Mail address.'; return $errorMsg; } } $email = "[email protected]"; try { try { // Check if "example" is in the email 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 above code checks if the email address contains the string "example". If it does, the exception is re-thrown:
The customException() class is created as an extension of the old exception class. This way, it inherits all properties and methods of the old exception class.
The errorMessage() function is created. If the email address is not valid, this function returns an error message.
Set the $email variable to a string that is a valid email address but contains the string "example".
The "try" block contains another "try" block, allowing for re-throwing of exceptions.
Since the email contains the string "example", an exception is triggered.
The "catch" block catches the exception and re-throws "customException".
The "customException" is caught, and an error message is displayed.
If the exception is not caught in the current "try" block, it will look for a catch block at a higher level.
Set Top-Level Exception Handler
The set_exception_handler() function can set 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 above code will be as follows:
Exception: Uncaught Exception occurred
In the above code, there is no "catch" block, but the top-level exception handler is triggered. This function should be used to catch all uncaught exceptions.
Exception Rules
Code that needs to handle exceptions should be placed inside a try block to catch potential exceptions.
Each try or throw block must have at least one corresponding catch block.
Multiple catch blocks can be used to catch different types of exceptions.
Exceptions can be thrown (re-thrown) within a catch block inside a try block.
In short: If an exception is thrown, it must be caught.