আগামী ১৫ ডিসেম্বর -২০১৭ তারিখ থেকে শুরু হচ্ছে পাঁচ মাস ব্যাপী Professional Web Design and Development with HTML, CSS PHP,MySQL,JavaScript, AJAX, JQUERY, Bootstrap and Live Project কোর্সের ৮৭ তম ব্যাচ এবং ২৬ ডিসেম্বর-২০১৭ তারিখ থেকে শুরু হচ্ছে চার মাস ব্যাপী Zend PHP-7 Certified PHP Engineering (Advance PHP) কোর্সের ৩৫ তম ব্যাচ। প্রত্যেকটি কোর্স এর ফী নির্ধারণ করা হয়েছে ৩০,০০০/= আগ্রহীদেরকে অতিসত্বর মাসুদ আলম স্যার এর সাথে যোগাযোগ করতে অনুরোধ করা যাচ্ছে। স্যার এর মোবাইল: 01722 81 75 91

Exceptions Handling with PHP

Exceptions Handling with PHP

What are Exceptions?

PHP Exceptions Handiling

With the advent of PHP 5 came the new OO model and a new Object Oriented approach of dealing with errors. Exceptions give us much better handling of errors an allow us to customize the behavior of our scripts when an error (Exception) is encountered.

Getting started

PHP EXceptions Catch

In its simplest form, exceptions are still quite powerful in that they allow us to catch errors where and when we want. In a more complex form Exception give us an alternative to the use of special error return codes to signal a function call failure. We can use them for each function of for a whole block of code. Let’s dive in and see what the fuss is about. Let’s create a file called exceptions1.php…

<?php
 /**
  *
  * @Check if number is greater than 3
  *
  * @param int
  *
  * @return bool on success
  *
  */
 function checkNum($number){
 if($number > 3)
     {
     throw new Exception('Number is greater than 3');
     }
 return true;
 }
 /*** call the function ***/
 checkNum(28);
 ?>

The above code will produce an error like this:

Fatal error:Uncaught exception ‘Exception’ with message ‘Number is greater than 3’ in /www/exception.php:15 Stack trace:#0 /www/exception.php(21):checkNum(28) #1 {main} thrown in /www/exception.php on line 15

The error is has occurred because an exception has been thrown in the checkNum function, but has not been caught. All exceptions need to be caught or this error will occur. An exception is caught using a catch block. But first we need to try the code that throws the exception. So the order of things is:

  • try
  • throw
  • catch

Just remember, if you throw something, you have to catch it. Let’s put it to the test with some valid code.

Exceptions2.php

<?php
 /**
  *
  * @Check if number is greater than 3
  *
  * @param int
  *
  * @return bool on success
  *
  */
 function checkNum($number){
 if($number > 3)
     {
     throw new Exception('Number is greater than 3');
     }
 return true;
 }
 /*** try block ***/
 try
     {
     checkNum(28);
     /*** this code does not get excecuted if an exception is thrown ***/
     echo 'If you see this, the number is not greater than 3';
     }
 /*** catch the exception here ***/
 catch(Exception $e)
     {
     // code to handle the Exception
     echo 'Catch exception here';
     echo 'Message:'   .$e->getMessage().'';
     echo 'More text or functions here.';
     }
 ?>

Lets step through the code and get a grip on what is happening. The function checkNum simply checks is a number is greater than 3. If it is not, and exception is thrown with an error message. Next we have a try { } block that makes a call to the checkNum() function. If the condition in the checkNum() function is not met, an exeption is thrown and will be caught in the first catch block. You may have more than one catch block. PHP will attempt to parse anything that appears in this code block until either an Exception is thrown or the end of the code block. Any code after an exception is thrown is not executed.

In the catch(){ } block, the code first echoes a line of text saying we have caught an exception, then the error message is contained in the call to $e->getMessage() method from the exception class. The error message is passed directly to the Exception class construct. When catching the thrown Exception, we assign the instance to a variable (object) for use in or code, and now we have an exception object containing our exception information. So, enough of the basics. As we follow this document, we will explore deeper…

Practice Example #1 Throwing an Exception

File:exceptions3.php

<?php
 function inverse($x) {
     if (!$x) {
         throw new Exception('Division by zero.');
     }
     else return 1/$x;
 }
 try {
     echo inverse(5) . '\n';
     echo inverse(0) . '\n';
 }
catch (Exception $e) {
     echo 'Caught exception:'.  $e->getMessage(). '\n';
 }
 // Continue execution
 echo 'Hello World';
 ?>

The above example will output:

0.2
Caught exception:Division by zero.
Hello World

Practice Example #2

File:exceptions4.php

<?php
function divide($x,$y){
if($y==0){
throw new Exception('Please Enter a value greater than 0');
}
else{
echo ' $x / $y ='. $x/$y;
}
}
try{
divide(100,0);
}
catch( Exception $e){
echo $e->getMessage();
}
?>

The above example will output:

100 / 5 =20
Please Enter a value greater than 0

Custom Exceptions

The Exception class, like most classes, can be extended to create our own custom exception classes. When a new class is based on a parent class As PHP uses unified constructors and allows inheritances. So when the Exception class is extended, all the methods are available to use. Lets take it for a run using a class to check for an invalid email address based on a value returned from the filter_var() function.

File:exceptions5.php

<?php
 class customException extends Exception {
 /**
  *
  * @return exception message
  *
  * @access public
  *
  * @return string
  *
  */
 public function exceptionMessage(){
  /*** the error message ***/
  $errorMsg = 'The email Address '.$this->getMessage().', on line '.
  $this->getLine().' in '.$this->getFile().', is invalid.';
  /*** return the error message ***/
  return $errorMsg;
 }
 } /*** end of class ***/
 ?>

The class above is essentially an exception class on its own. It has the single addition of the exceptionMessage() method that calls the Exception class methods getLine() and getFile() and getMessage(). As they are defined in the base class, the extended class *inherits* from it. Let’s take it for a test drive.

Practice Example #3

File:exceptions6.php

<?php
 /*** an invalid email address ***/
 $email = '[email protected]@com';
 try    {
     /*** check the validity of the email address ***/
     if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
         {
         /*** if there is a problem, throw an exception ***/
         throw new customException($email);
         }
     }
 catch (customException $e)
     {
     /*** display the custom error message ***/
     echo '<p style="color:red">'.$e->errorMessage().'</p>';
     }
 /*** the custome excetpion class ***/
 class customException extends Exception {
 /**
  *
  * @return exception message
  *
  * @access public
  *
  * @return string
  *
  */
 public function errorMessage(){
  /*** the error message ***/
  $errorMsg = 'The email Address '.$this->getMessage().', on line '.
  $this->getLine().' in '.$this->getFile().', is invalid.';
  /*** return the error message ***/
  return $errorMsg;
 }
 } /*** end of class ***/
 ?>

Output:

The email Address [email protected]@com, on line 10 in F:\wamp\www\exceptions\exceptions6.php, is invalid.

Obviously the email address supplied is invalid and when the filter_var() function returns bool FALSE an exception is thrown to the customException class. The exception is thrown as would any normal exception. Even though the only argument passed to the customException class is the $email variable, all the methods available to the parent Exception class are available, such as getMessage(), getLine() and getFile(). Because the PHP OO model includes unified constructors, when the $email variable is passed to the customException class, it is immediately available to the parent class. But this example shows only how to try, throw, and catch a single exception. There are times when we need more than this. Multiple exceptions can be thrown a caught also.

Practice Example #4

File:exceptions7.php

<?php
class CheckNumber extends Exception{
function errorMessage(){
return 'Your Given No '. $this->getMessage().' is not Integer Number';
}
}
$num=1.5;
try{
if(filter_var($num,FILTER_VALIDATE_INT)===FALSE){
throw new CheckNumber($num);
}
else{
echo'Your given No '.$num.' is a Integer Value';
}
}
catch(CheckNumber $e){
echo $e->errorMessage();
}
?>

Multiple Exceptions

PHP Multiple Exceptions Handling

Multiple exceptions can take many forms. they can be in a multiple if/else blocks, in a switch, or nested. Yes, you can nest exceptions in multiple try{ } catch(){ } blocks. A script may need to check for multiple conditions and different messages returned. Program flow may also need to change if an exception is thrown. Let’s see how we can nest an exception and check for different error conditions. The customException class need not change for this. This is what is meant in PHP as re-usable code. Here we see an example of using nested try{ } catch(){ } blocks.

File:exceptions8.php

<?php
 $email = '[email protected]';
 try    {
     if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
         {
         throw new customException($email);
         }
     try    {
         if(strpos($email, 'gmail') !== FALSE)
             {
             throw new Exception('$email is funky');
             }
         }
     catch(Exception $e)
         {
         echo '<p style="color:blue">'.$e->getMessage().'</p>';
         }
     }
 catch (customException $e)
     {
     echo '<p style="color:red">'.$e->errorMessage().'</p>';
     }
 class customException extends Exception {
 /**
  *
  * @return exception message
  *
  * @access public
  *
  * @return string
  *
  */
 public function errorMessage(){
  /*** the error message ***/
  $errorMsg = 'The email Address '.$this->getMessage().', on line '.
  $this->getLine().' in '.$this->getFile().', is invalid.';
  /*** return the error message ***/
  return $errorMsg;
 }
 } /*** end of class ***/
 ?>

In the above example, the colors of the errors have been made red or blue to easily discern which error has been thrown. The problem with this sort of code, or nested if/else blocks, is if the program calls for large amounts of validation, we end up with very deeply nested code which can become very clumsy to read and debug. A better option is simply to code smarter. Lets look at an option using only single if() blocks to check a condition.

File:exceptions9.php

<?php
 $email = '[email protected]';
 try    {
     /*** check if email is valid ***/
     if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
         {
         throw new customException($email);
         }
     /*** check for fish ***/
     if(strpos($email, 'fish') !== FALSE)
         {
         throw new Exception('$email is funky');
         }
     /*** check for example.org ***/
     if($email !== '[email protected]');
         {
         throw new customException($email);
         }
     }
 catch(customException $e)
     {
     echo '<p style="color:red">'.$e->errorMessage().'</p>';
     }
 catch(Exception $e)
     {
     echo '<p style="color:blue">'.$e->getMessage().'</p>';
     }
 class customException extends Exception {
 /**
  *
  * @return exception message
  *
  * @access public
  *
  * @return string
  *
  */
 public function errorMessage(){
  /*** the error message ***/
  $errorMsg = 'The email Address '.$this->getMessage().', on line '.
  $this->getLine().' in '.$this->getFile().', is invalid.';
  /*** return the error message ***/
  return $errorMsg;
 }
 } /*** end of class ***/
 ?>

The above coding style makes much better sense and is much easier to follow and to read. Two catch(){ } blocks have been used in this code, as the Exception implementation allows for multiples. Once again the errors are color coded and this time we see that PHP has successfully jumped to the correct catch(){ } block corresponding to the thrown error. In this case, the $email variable has the word *fish* in it and so a standard exception is thrown, and caught in the appropriate catch(){ } block. If the customException catch block was omitted, and only the base Exception catch block was available, the Exception would be handled there.

Re-throwing Exceptions

PHP Exceptions Rethrowing

An exception may be re-thrown when you wish to govern program flow. If a condition is not met, and an exception is thrown, you may wish to handle it differently based on a second condition or you may wish to try and recover from the error. It is generally considered practice to hide system errors from users. Lets consider a simple database connection with PDO. Because PDO is so totally amazing, it has a built in exceptions. If an error occurs when trying to connect to the database an exception is thrown and must be caught. While an error from the database may be meaningful to the person coding the application, it has little or no relevance to the user. So the exception can be re-thrown with a nice friendly message that the user is more likely to understand. Eg:a failed PDO database error would look like this:
SQLSTATE[HY000] [14] unable to open database file
When re-throwing errors from lower levels such as this, the exception must be wrapped inside the one being thrown. If the exception is not wrapped and caught, it will continue to “bubble up” the stack until it finds a catch(){ } block to handle it. If no catch(){ } block is found, and uncaught exception error will result. The example below demonstrates how to properly re-throw an exception.

File:exceptions10.php

<?php
 try    {
     try    {
         /*** try to connect to a non-existant database ***/
         $db = new PDO('sqlite:/path/to/database.sdb');
         }
     catch(PDOException $e)
         {
         /*** rethrow the error to the custom handler ***/
         throw new customException('Database unavailable');
         }
     }
 /*** catch the customException here ***/
 catch(customException $e)
     {
     /*** echo the new error message ***/
     echo $e->errorMessage();
     }
 class customException extends Exception {
 /**
  *
  * @return exception message
  *
  * @access public
  *
  * @return string
  *
  */
 public function errorMessage(){
  /*** the error message ***/
  $errorMsg = '<p style="color:red;">'.$this->getMessage().'</p>';
  /*** return the error message ***/
  return $errorMsg;
 }
 } /*** end of class ***/
 ?>

From the code above we see a PDO exception is thrown when we try to connect to a non-existant database. This exception is caught and re-thrown with the customException class that handles the error and gracefully exits. Any un-caught Exception should be considered an application bug.

Program Flow with Exceptions

Exceptions should not be used as a GOTO, even though they seem ideally suited for the purpose. A good exception implantation means the code will work without any of the try{} catch{} blocks. The Exception class should only be used error conditions. Below is an example of incorrect Exception usage.

File:exceptions11.php

<?php
 $animalsArray = array('dingo', 'wombat', 'steve irwin', 'kiwi', 'kangaroo', 'platypus');
 try    {
     /*** loop over the array ***/
     foreach($animalsArray as $value)
         {
         /*** if we find a kiwi ***/
         if($value == 'kiwi')
             {
             /*** throw an exception here ***/
             throw new Exception('This is not an Australian Native');
             }
         }
     }
 catch(Exception $e)
     {
     /*** catch the exception here ***/
     echo $e->getMessage();
     }
 ?>

The script above throws the exception when a value is found in the foreach loop. This is an abuse of the Exceptions class as a simple break here would have done the same job cleanly. No error has occured, so no Exception should be thrown.

Top Level Exception Handler

PHP Top Level Exceptions Handling

A most amazing feature of PHP is the set_exception_handler() function. This little charmer takes care of un-caught exceptions in what amounts to a last chance to catch any previously uncaught Exceptions, ie:if any Exception is not caught in a catch(){} block. This function takes a callback exception_handler as its only arguement which must be defined before any call to it. The default_handler will take a single parameter that is Exception object that has been thrown. This script below shows the workings.

File:Exceptions12.php

<?php
 /*** a default Exception handler ***/
 function my_default_handler($exception){
   echo 'Uncaught exception:' . $exception->getMessage();
 }
 /*** set the default to handler to my_default_handler ***/
 set_exception_handler('my_default_handler');
 /*** throw an exception ***/
 throw new Exception('Catch me if you can!');
 echo 'This is not executed';
 ?>

If you wanted to restore the default Exception handler, simple use the restore_exception_handler(); function. This could also be used if your current default handler was another custom Exception class. The Exception classes are held in a stack can be restored with the restore_exception_handler() function as shown here.

File:exceptions13.php

<?php
 /*** an email to validate ***/
 $email = '[email protected]';
 /*** red error messages ***/
 function blue_default_handler($exception){
   echo '<p style="color:blue;">'.$exception->getMessage().'</p>';
 }
 /*** blue error messages ***/
 function red_default_handler($exception){
   echo '<p style="color:red;">'.$exception->getMessage().'</p>';
 }
 /*** set the default to handler to red_default_handler ***/
 set_exception_handler('red_default_handler');
 /*** some code here ***/
 if(!isset($email))
     {
     /*** if there is no match ***/
     throw new exception('No Email is set');
     }
 /*** set the default handler to blue_default_handler ***/
 set_exception_handler('blue_default_handler');
 /*** check the email value ***/
 if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
     {
     throw new Exception('Invalid Email');
     }
 /*** restore the default handler ***/
 restore_exception_handler();
 if(strpos($email, 'guru') !== false)
     {
     throw new Exception('Sorry, No gurus at gmail');
     }
 echo 'This is not executed';
 ?>

So, from the script above we see the declaration of two Exception handlers, one makes the error messags red, and the other makes them blue. This is perhaps an abuse of the Exception functionality but serves well to demonstrate changes in classes as they occur. The initial default handler is set to red. The a check is run to see if an $email variable is set. Try removing the $email variable or commenting it out to see it work. If the $email varible is set, the code continues and the default handler is set to the blue_default_handler. Then using the filter_var() function, the $email is tested for validity and if it fails, a blue message is shown. Try changing the value of the email to 1234 to see the results. Finally we see the use of restore_exception_handler(); which pops the stack and returns the default Exception handler to the red_default_handler. When any of these exceptions occur, code execution stops and control is passed to the handler. You notice at the bottom of the script above that the line
echo ‘This is not executed’; is never executed. But.. what if we wish to continue with the script and execute code below the thrown exceptions? This is the default behavior of Exceptions. Once outside the catch(){ } block you are free to include whatever code you wish.

Output buffering is Off by default in php.ini so it will need to be turned on via ob_start(). We can begin output to the brower in the script and if an exception is thrown, still use header() to redirect based on the exception type.

<?php
 try {
     /*** try to connect to a non-existent database ***/
     $dsn = new PDO('sqlite:/path/to/database.php');
     /*** this code is never executed ***/
     echo 'Move along, nothing to see here';
     }
 catch (PDOException $e)
     {
     /*** echo the error message ***/
     echo '<h4>Database Error:' . $e->getMessage() . '</h4>';
     }
 /*** more code and HTML here ***/
 echo 'Catch me if you can!';
 ?>

Error Codes

As seen in the beginning of this document, the Exception class contains a getCode() method that will fetch an error code, this can useful as you can define your own error codes as well as your own error messages. This quick demonstration shows how.

File:exceptions14.php

<?php
 /*** an invalid email address ***/
 $email = '[email protected]@org';
 try    {
     /*** validate the email address ***/
     $db = validateEmail($email);
     }
 catch (Exception $e)
     {
     /*** display the error code ***/
     echo 'Error:' . $e->getCode();
     }
 /**
  *
  * @validate an email
  *
  * @param string
  *
  * @throw standard exception on failure
  *
  */
 function validateEmail($email){
   if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
     {
     throw new Exception('Invalid Email', 10);
     }
 }
 ?>

The above code returns the line:
Error:10
Well, big deal you say.. Ok, if we can define our own error codes, we can script based on thier value! The following script shows some of the possibilities.

<?php
	/*** an invalid email address ***/
 $email = '[email protected]@org';
 try    {
     /*** validate the email address ***/
     $db = validateEmail($email);
     }
 catch (Exception $e)
     {
     /*** display the error code ***/
     switch ($e->getCode()) {
     case 0:
       echo 'Handle error here';
       break;
     case 10:
       echo 'Handle error condition here';
       break;
     case 20:
       echo 'handle other condition here';
       break;
     default:
     echo 'some default handler here';
     }
 }
 /**
  *
  * @validate an email
  *
  * @param string
  *
  * @throw standard exception on failure
  *
  */
 function validateEmail($email){
   if(filter_var($email, FILTER_VALIDATE_EMAIL) === FALSE)
     {
     throw new Exception('Invalid Email', 10);
     }
 }
 ?>

The error code generated when we the Exception is thrown is used in the switch block to choose how the script will be have next. You can probably think up your own uses for generating codes.

Here’s a list of an exception’s methods:

  • getMessage() – gets the exception’s message
  • getCode() – returns a numerical code that represents the exception
  • getFile() – returns the file where the exception was thrown
  • getLine() – returns the line number in the file where the exception was thrown
  • getTrace() – returns the an array of the backtrace() before the exception was thrown
  • getPrevious() – returns the exception thrown before the current one, if any
  • getTraceAsString() – returns the backtrace() of an exception as a string instead of an array
  • __toString() – returns the whole exception as a string. Is overrideable.

Summary

The PHP Exceptions class can be a very useful and significant tool to aid in the reporting and handling of errors. There is also room for abuse of the class and it is hoped that this document will point out the failings of using them so.

Hi, My name is Masud Alam, love to work with Open Source Technologies, living in Dhaka, Bangladesh. I’m a Certified Engineer on ZEND PHP 5.3, I served my first five years a number of leadership positions at Winux Soft Ltd, SSL Wireless Ltd, Canadian International Development Agency (CIDA), World Vision, Care Bangladesh, Helen Keller, US AID and MAX Group where I worked on ERP software and web development., but now i’m a founder and CEO of TechBeeo Software Company Ltd. I’m also a Course Instructor of ZCPE PHP 7 Certification and professional web development course at w3programmers Training Institute – a leading Training Institute in the country.

2 comments on “Exceptions Handling with PHP

Leave a Reply

Your email address will not be published. Required fields are marked *