on Basics Tutorials

PHP Exceptions

2 comments
secure-coding-php
Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon

PHP 5 has an exception model similar to that of other programming languages (like Java). An exception can be thrown, and caught within PHP.

Code can be surrounded in a try block, to facilitate the catching of potential exceptions. Each try must have at least one corresponding catch block.

Multiple catch blocks can be used to catch different classes of exceptions. Normal execution (when no exception is thrown within the try block, or when a catch matching the thrown exception’s class is not present) will continue after that last catch block defined in sequence.

Enough said, let me show you a basic example:

class Generic 
  {
      
      private $someVar;
      
      public function __construct($someVar) 
      {
          $this->someVar = $someVar;
      }
      
      public function testValue($someOtherVar)
      {
          if($someOtherVar > 3) {
              throw new Exception('Method parameter can not be larger then 3!');
          } else {
              echo $this->someVar + $someOtherVar;
          }
      }
  }
  
  $gen = new Generic(3);
  $gen->testValue(4);

This is some really generic code to show you how exceptions are handled. If you try this you will get a response like this:

Fatal error: Uncaught exception ‘Exception’ with message ‘Parameter can not be larger then 3!’ in C:\wamp\www\privat\codeforest\exceptions\index.php:15 Stack trace: #0 C:\wamp\www\privat\codeforest\exceptions\index.php(23): Generic->testValue(4) #1 {main} thrown in C:\wamp\www\privat\codeforest\exceptions\index.php on line 15

That is because I didn’t put try and catch blocks to handle the exception. So, to do it properly, our code should look like this:

  try 
  {
      $gen = new Generic(3);
      $gen->testValue(4);
  } catch (Exception $e) {
      // code to handle the Exception
      echo 'Catch exception here<br />';
      echo 'Message: '   . $e->getMessage() . '<br />';
      echo 'Some more info goes here!';
  }

Now, the exception is caught and our exception message is displayed on the screen.

It’s possible to get detailed information about the error that occurred. It’s precisely for this reason that the Exception class provides developers with some other methods, which can offer additional details about the failure and its environment.

This is how to implement this other methods in our little example:

try 
  {
        $gen = new Generic(3);
        $gen->testValue(4);
  } catch (Exception $e) {
        // code to handle the Exception
        echo 'Error :' . $e->getMessage() . '<br />';
        echo 'Code :' . $e->getCode() . '<br />';
        echo 'File :' . $e->getFile() . '<br />';
        echo 'Line :' . $e->getLine() . '<br />';
        exit();
  }

Returning to the example above, it’s nearly the same as the previous one. However, the catch block uses the additional methods of the exception object, helpful for obtaining more specific details on the error that occurred. With reference to this, the set of echo statements displays the error message passed in when the exception was originally thrown, as well as the error code (if any), the file containing the error, and finally the line at which the failure happened.

Now, the benefits of exceptions should be pretty clear. Notice how easy it is to set up an error management mechanism that can be developed through specific code, while maintaining program flow completely free from dealing with potential failures. In addition a greater level of detail on the error that occurred can be easily obtained by calling up some of the complementary built-in methods.

Consider this example:

  class Generic 
  {
      
      private   $someVar, $result;
      const     NUM_ERROR       = 1;
      const     ANY_ERROR       = 2; 
      
      public function __construct($someVar) 
      {
          $this->someVar = $someVar;
      }
      
      public function testValue($someOtherVar)
      {
          if($someOtherVar > 3) {
              throw new Exception('Parameter can not be larger then 3!', self::NUM_ERROR);
          } else {
              $this->result = $this->someVar + $someOtherVar;
              echo $this->result . '<br />';
          }
      }
      
      public function otherMethod() 
      {
          if($this->result > 4) {
              throw new Exception('The result is greater then 4.', self::ANY_ERROR);
          }    
      }
  }
  
  // let's do it
  try 
  {
        $gen = new Generic(3);
        $gen->testValue(2);
        $gen->otherMethod();
  } catch (Exception $e) {
        if($e->getCode() == 1) {
            die ($e->getMessage());
        } else {
            echo 'Error :' . $e->getMessage() . '<br />';
            echo 'File :' . $e->getFile() . '<br />';
            echo 'Line :' . $e->getLine() . '<br />';
            exit();            
        }
  }

Now, with the introduction of a few modifications to the original sample class, I’ve set up a more efficient error handler, which can react differently, based on the second error parameter passed to client code. Certainly, it’s possible to use all the methods of the Exception class shown above, and develop an error handing mechanism capable of giving detailed information on the failure and its context.

But, there is one more thing you can do. Create your own Exception handler. Creating a custom exception handler is quite 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.

The custom exception class inherits the properties from PHP’s exception class and you can add custom methods to it.

Consider this example:

class Generic 
  {
      
      private   $someVar, $result;
      const     NUM_ERROR       = 1;
      const     ANY_ERROR       = 2; 
      
      public function __construct($someVar) 
      {
          $this->someVar = $someVar;
      }
      
      public function testValue($someOtherVar)
      {
          if($someOtherVar > 3) {
              throw new CustomException('Parameter can not be larger then 3!', self::NUM_ERROR);
          } else {
              $this->result = $this->someVar + $someOtherVar;
              echo $this->result . '<br />';
          }
      }
      
      public function otherMethod() 
      {
          if($this->result > 4) {
              throw new CustomException('The result is greater then 4.', self::ANY_ERROR);
          }    
      }
  }
  
  class CustomException extends Exception
  {
  
      public function logError()
      {
            // Send notification through the server log
            if($this->getCode() == Generic::NUM_ERROR){
                error_log($this->getMessage(), 0);
            }
            // Notify administrator by email
            else if($this->getCode() == Generic::ANY_ERROR){
                error_log($this->getMessage(), 1, 'sysadmin@domain.com');
            }
      }
}
  
  // let's do it
  try 
  {
        $gen = new Generic(3);
        $gen->testValue(2);
        $gen->otherMethod();
  } catch (CustomException $e) {
        $e->logError();
  }

Here we are using our own Exception handler class CustomException to handle the Exception logic.

Definitely, the above script is now much simpler to code and read, due to the fact that all the exceptions are handled by the logError() method. Although the customized exception class is basic in its conception, it’s a useful example aimed at showing in a friendly way how to use Inheritance for deriving child exception handling classes.

PHP has a nifty function called set_exception_handler which sets a user-defined function to handle all uncaught exceptions:

function myException($exception)
    {
        echo "<strong>Exception:</strong> " , $exception->getMessage();
    }

set_exception_handler('myException');

throw new Exception('Uncaught Exception occurred');

The PHP Exceptions class can be a very useful and significant tool to aid in the reporting and handling of errors. There is more things to do here, like writing a custom Exception handler for different environments (like development and production) which will output exception messages to screen or log them in some log file.

Tweet about this on TwitterShare on FacebookShare on Google+Share on LinkedInShare on RedditShare on StumbleUpon