Article

PHP5: Coming Soon to a Webserver Near You

Page: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Next

Error Handling

PHP5 introduces a new error handling mechanism that’s in line with languages like Java and (dare I say it) JavaScript.

To understand how it works, it's worth looking at the current situation with PHP4. Essentially, the problem PHP developers face right now is how to separate error notifications in their code from application data. For example, consider the following:

           
<?php            
function searchColors ($color) {            
   // An error: $color must be longer than three characters            
   if ( strlen($color) < 3 )            
       return false;            
           
   $colors = array ('red','blue','green');            
           
   if ( in_array($color,$colors) )            
       // Yes there was a search match            
       return true;            
   else            
       // No there was no match            
       return false;            
}            
           
// Initialize variable            
if ( !isset($_GET['color']) )            
   $_GET['color']='white';            
           
if ( !searchColors($_GET['color']) ) {            
   echo ( 'Search for '.$_GET['color'].' returned no matches' );            
} else {            
   echo ( $_GET['color'].' was found!' );            
}            
?>            

Script: exception.php

The searchColors() function is intended to return true if the color argument is found in the $colors array, and false if it isn't found. Both of these returned values could be considered as valid application data. But there's a problem. The $color value submitted to the searchColors() function must be at least three characters long (perhaps in a real world example this is because my database server can only perform FULLTEXT searches on search strings of a minimum length). Should it not meet the three character requirement, the script returns false. The problem is, how does the code calling the function know which "false" is valid application data, and which is an error?

Perhaps I could return -1 if the string length test fails, to distinguish it from a false value, but that's going to lead to some pretty ugly code when I use the function to perform an additional check for that value. Also, I should use that approach consistently throughout my application, which, if I'm forgetful or working in a team, may be a problem.

Alternatively, I might consider turning to PHP's trigger_error() function, which will at least allow the error to be dealt with separately from the code that calls the function. It can define a "global" error handler with set_error_handler, but trying to get the handler to understand where the error came from, and what the appropriate response is, will be awkward. I really want to be able to deal with this error somewhere near the point at which the searchColors() function is called.

Note: For an in depth look at error handling with version 4, try Error Handling in PHP.

PHP5's new mechanism introduces a control structure, the try/catch condition, which is a lot like an if/else, but has been designed specifically for handling a special type of value—the Exception. If you haven't come across try/catch type error handling in another programming language, it may seem a little strange at first; once you get used to it, though, I'm sure you'll find it's a big relief. It's worth remembering that the idea behind this approach is to separate application data from errors.

Using the new mechanism, the above example might look like this:

           
<?php            
function searchColors ($color) {            
   // An error: $color must be longer than three characters            
   if ( strlen($color) < 3 )            
       // throw an Exception            
       throw new Exception('Color is too short. 3 chars min');            
           
   $colors = array ('red','blue','green');            
           
   if ( in_array($color,$colors) )            
       // Yes there was a search match            
       return true;            
   else            
       // No there was no match            
       return false;            
}            
           
// Initialize variable            
if ( !isset($_GET['color']) )            
   $_GET['color']='white';            
           
// Try the search colors function            
try {            
           
   if ( !searchColors($_GET['color']) ) {            
       echo ( 'Search for '.$_GET['color'].' returned no matches' );            
   } else {            
       echo ( $_GET['color'].' was found!' );            
   }            
           
// Catch an thrown exceptions here            
} catch (Exception $e) {            
   echo ( $e->getMessage() );            
}            
?>            

Script: exception1.php

First, notice that the searchColors() function, when encountering a search string that’s too short, now uses the keyword throw to create an object of class Exception. This class is built into PHP5, so it’ll always be available. More on Exception in a moment.

Now in the code that uses the searchColors() function, I place my old PHP4 code inside the try{} block. It now only has to deal with application data, not errors. If a search string that’s too short is passed to searchColors(), an Exception object is thrown and execution of searchColors() immediately stops. Control now passes to the catch{} block where the error can be handled separately from the normal flow of the application, in this case displaying a message that the color provided was too short.

Using try/catch exception handling, in some situations I may be able to have my code "recover" from the error. For example:

           
<?php            
// Define my own subclass            
class DivideByZeroError extends Exception {            
   function __construct($message) {            
       parent::Exception($message);            
   }            
}            
           
function divide($by) {            
   if ( $by == 0 )            
       throw new DivideByZeroError ('Divide by Zero Error');            
   return 1 / $by;            
}            
           
// Initialize variable            
if ( !isset($_GET['divideBy']) ) {            
   $_GET['divideBy'] = 1;            
}            
           
try {            
           
   echo ( divide($_GET['divideBy']) );            
           
} catch (DivideByZeroError $e) {            
           
   // Make a small value slightly bigger than zero            
   $_GET['divideBy'] = 0.0000000000000001;            
           
   // Re-execute the divide() function            
   echo ( divide($_GET['divideBy']) );            
           
}            
?>            

Script: exception2.php

The first thing to notice in the above example is that I've defined my own exception class, DivideByZeroError, which extends the built-in Exception class. Note that with the PHP5 Beta, the built in Exception class does not have a __construct() method so inside the DivideByZeroError class I have to call the parent constructor by name.

The catch{} block is on the look out for DivideByZeroError exceptions. Should it encounter one, it modifies the value being divided by to a small number very slightly bigger than zero then re-runs the divide() function. This, I've decided, is acceptable within the context of my application.

So, as you’re aware, the Exception class (currently) has four built-in methods, and is able to accept an additional error code argument to its constructor:

           
<?php            
try {            
   throw new Exception ( 'This is an error',54321 );            
} catch (Exception $e) {            
   echo ( 'Error message: '.$e->getMessage().'<br />' );            
   echo ( 'Error code: '.$e->getCode().'<br />' );            
   echo ( 'Script Name: '.$e->getFile().'<br />' );            
   echo ( 'Line Number: '.$e->getLine().'<br />' );            
}            
?>            

Script: exception3.php

As well as being able to define your own subclasses of Exception (to which you could add additional methods), you might use the error codes to distinguish between two exceptions of the same type.

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links