PHP Exception Handling

Exception (Exception) is used to change the normal flow of the script when a specified error occurs.

What is an exception?

PHP 5 provides a new object-oriented error handling method.

Exception handling is used to change the normal flow of the script when a specified error (exception) occurs. This situation is called an exception.

When an exception is triggered, the following usually occurs:

  • The current code state is saved
  • Code execution is switched to the predefined exception handler function
  • Depending on the situation, the handler may restart execution of the code from a saved code state, terminate script execution, or continue executing the script from another location in the code

We will demonstrate different error handling methods:

  • Basic usage of exceptions
  • Creating a custom exception handler
  • Multiple exceptions
  • Rethrow exception
  • Setting a top-level exception handler

Basic usage of exceptions

When an exception is thrown, the code following it will not continue to execute, and PHP will try to find a matching 'catch' block.

If an exception is not caught and no corresponding handling is done with set_exception_handler(), a serious error (a fatal error) will occur, and the error message 'Uncaught Exception' will be output.

Let's 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 above code will generate an error similar to this:

Fatal error: Uncaught exception 'Exception' 
with message 'Value must be 1 or below' in C:\webfolder\test.php:6 
Stack trace: #0 C:\webfolder\test.php(12): 
checkNum(28) #1 {main} thrown in C:\webfolder\test.php on line 6

Try, throw, and catch

To avoid the error that occurred in the above example, we need to create appropriate code to handle exceptions.

The proper handler should include:

  1. Try - The function that throws an exception should be located inside a 'try' block. If no exception is thrown, the code will continue to execute normally. However, if an exception is triggered, an exception will be thrown.
  2. Throw - Here it is specified how to trigger an exception. Every "throw" must be matched with at least one "catch"
  3. Catch - The "catch" block will catch the exception and create an object containing exception information

Let's trigger an exception:

<?php
//Create a function that can throw an exception
function checkNum($number)
 {
 if($number>1)
  {
  throw new Exception("Value must be 1 or below");
  }
 return true;
 }
//Trigger an exception in the "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 above code will produce an error similar to this:

Message: Value must be 1 or below

Example explanation:

The above code throws an exception and catches it:

  1. Create the checkNum() function. It checks if the number is greater than 1. If it is, it throws an exception.
  2. The checkNum() function is called within the "try" block.
  3. An exception is thrown in the checkNum() function.
  4. "Catch" block receives the exception and creates an object containing exception information ($e).
  5. By calling $e->getMessage() from this exception object, the error message from the exception is output.

However, to follow the principle of 'each throw must have a corresponding catch', you can set a top-level exception handler to handle missing errors.

Create a custom Exception class

Creating a custom exception handler is very simple. We simply create a special class whose functions can be called when an exception occurs in PHP. This class must be an extension of the exception class.

This custom exception class inherits all properties of the PHP exception class, and you can add custom functions to it.

We begin to create the 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();
 }
?>

This new class is a copy of the old exception class, plus the errorMessage() function. Because it is a copy of the old class, it inherits properties and methods from the old class, and we can use methods of the exception class, such as getLine(), getFile(), and getMessage().

Example explanation:

The above code throws an exception and catches it through a custom exception class:

  1. The customException() class is created as an extension of the old exception class. This way, it inherits all properties and methods of the old class.
  2. Create the errorMessage() function. If the e-mail address is invalid, the function returns an error message
  3. Set the $email variable to an invalid e-mail address string
  4. Execute the 'try' block, an exception is thrown due to the invalid e-mail address
  5. The 'catch' block catches the exception and displays the error message

Multiple exceptions

You can use multiple exceptions for a script to detect multiple situations.

You can use multiple if..else blocks, or one switch block, 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 explanation:

The above code tests two conditions, if any condition is not met, an exception will be thrown:

  1. The customException() class is created as an extension of the old exception class. This way, it inherits all properties and methods of the old class.
  2. Create the errorMessage() function. If the e-mail address is not valid, the function returns an error message.
  3. Execute the 'try' block, no exception will be thrown under the first condition.
  4. Since the e-mail contains the string 'example', the second condition will trigger the exception.
  5. The 'catch' block catches the exception and displays the appropriate error message

If customException is not caught, and only base exception is caught, handle the exception there.

Rethrow exception

Sometimes, when an exception is thrown, you may want to handle it in a way different from the standard. You can rethrow the exception again in a 'catch' block.

The script should hide system errors from the user. While system errors may be important for programmers, users are not interested in them. To make it easier for users, you can re-throw exceptions with messages that are more user-friendly:

<?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 explanation:

The above code checks if the string "example" is present in the e-mail address. If it is, the exception is thrown again:

  1. The customException() class is created as an extension of the old exception class. This way, it inherits all properties and methods of the old class.
  2. Create the errorMessage() function. If the e-mail address is not valid, the function returns an error message.
  3. Set the $email variable to a valid email address, but it contains the string "example".
  4. The "try" block contains another "try" block, allowing the exception to be thrown again.
  5. An exception was triggered because the e-mail contains the string "example".
  6. "catch" caught the exception and re-threw "customException".
  7. Caught "customException" and displayed an error message.

If an exception is not caught in its current 'try' code block, it will look for a catch block at a higher level.

Setting 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 should be similar to this:

Exception: Uncaught Exception occurred

In the above code, there is no 'catch' block, but the top-level exception handling program is triggered. This function should be used to catch all uncaught exceptions.

Rules of Exceptions

  • Code that needs to handle exceptions should be placed within a try block to catch potential exceptions.
  • Each try or throw block must have at least one corresponding catch block.
  • Using multiple catch blocks can catch different types of exceptions.
  • An exception can be re-thrown (re-thrown) within a catch block in the try code block.

In short: If an exception is thrown, it must be caught.