Error Handling in PHP: Coding Defensively

As with any programming language, when you code in PHP, it helps immensely if you set up your applications to handle errors gracefully. This article explores some of the most common error checking methods available in PHP, and provides hands-on examples that use different error handling methods.

Introduction

Getting started with PHP is quite easy. Armed with a good PHP editor, any beginner can create a simple database-driven web application with minor hassles. Moreover, given a little more time, an average developer can pick up a good understanding of object-oriented programming and start working with classes and objects. Definitely, this sounds like a good and exciting thing — except for when,  during the development of an application, one has to write error handling code.

Let’s be honest. For novice (and not so novice) programmers, coding error handling routines is boring stuff. Even when it’s something that you can’t hide from very often, error manipulation usually is limited to writing a few “die()/exit()” statements when connecting to a database server, and some additional checking lines for handling potential errors within program execution. From a realistic point of view, the things about error handling is that if you’re developing a web application which lacks decent error checking code (due to ignorance or laziness), sooner or later your application will fail ungracefully. The result of this will be possibly the occurrence of potentially harmful errors — particularly in the area of security — and the display of ugly messages, making the whole program look very unprofessional.

Since error handling is something that you should introduce (at least progressively) into your applications, in this article I’ll explore some of the most common error checking methods available in PHP, in order to make web applications much more robust and reliable. The end result of this experience will be an illustrative list of hands-on examples that utilize different error handling methods, ranging in from using simple “die()” statements, to manipulating errors within an object-oriented context, by utilizing exceptions.

Having drawn the general guidelines for this tutorial, it’s time to dive into the topic and turn error handling into an instructive journey. Let’s get started.

{mospagebreak title=Killing your scripts: basic error handling with the “die()” statement}

The first example that implements the basics of script-level error handling is based on the popular “die()” statement. For this reason, I’ll write a simple PHP class, which reads contents from a data file. In its basic incarnation, this class looks like this:

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    $this->file=$file;
  }
  function getContent(){
    return file_get_contents(“{$this->fileDir}{$this->file}.php”);
  }
}

 

As I mentioned earlier, the above class implements a trivial file reader. Aside from the constructor, the class exposes only one public method, “getContent()”, which reads the content from a file passed in as an argument to the constructor. As you can see, the class has been coded with no error checking lines, so any object instantiated from it will cause a non-fatal error if the “$file” parameter doesn’t point to a valid file. The lines below show this circumstance:

// instantiate FileReader object
// pass in invalid file to the constructor
$fr=new FileReader(‘inexistent_file’);
// echo file content
echo $fr->getContent();

Warning: file_get_contents(fileDir/.php): failed to open stream: No such file or directory in /path/to/file/exceptions.php on line 4.

Although the example is rather crude, it demonstrates in a nutshell how a class written without any error handler can be easily broken up. Now, in order to implement a basic error handler, I’m going to include some “die()” statements within the class methods, as follows:

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    if(!file_exists(“{$this->fileDir}{$file}.php”)){
      die(‘File ‘.$file.’ not found’);
    }
    $this->file=$file;
  }
  function getContent(){
    if(!$content=file_get_contents(“{$this->fileDir}{$this->file}.php”)){
      die(“Unable to read file contents”);
    }
    return $content;
  }
}

 

Now, the class looks subtly better and more efficient. Notice how a couple of “die()” statements allow you to code defensively, and introduce an appreciable difference compared to the earlier version. In this case, if I instantiate a new “file reader” object, by pointing it to an inexistent file, this is what I should get as a result:

// instantiate FileReader object
$fr=new FileReader(‘inexistent_file’);
// echo file content
echo $fr->getContent();

File inexistent_file not found.

As you can see, the above snippet is a little more efficient, because it implements a simple error handling mechanism. Instead of leaving out of control conflictive operations, such as reading file contents, the class is capable at least of stopping program execution if an error occurs. Indeed, this is a considerable improvement from a programming point of view, and certainly didn’t demand any hard work from us.

However, pseudo functions like “die()” statements are rather inflexible. After all, it doesn’t always happen that a script must be abruptly terminated. Fortunately, PHP exposes other functions which are more helpful and flexible for handling errors. Considering this, let’s move on and have a look at the PHP built-in “trigger_error()” function, in order to find out how it can be used.

{mospagebreak title=Triggering errors: more efficient error handling with the “trigger_error()” function}

As I explained in earlier examples, the “die()” statement can be used to build in rudimentary error handling mechanisms. But, particularly in mid-sized and large applications, this method isn’t flexible enough. As I said before, PHP provides developers with the “trigger_error()” function, which can be utilized for developing a slightly more sophisticated error handler.

Let’s return to the sample class written earlier, and see how this function can be used for writing defensive code:

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    if(!file_exists(“{$this->fileDir}{$file}.php”)){
      trigger_error(‘File ‘.$file.’ not found’,E_USER_WARNING);
    }
    $this->file=$file;
  }
  function getContent(){
    if(!$content=file_get_contents(“{$this->fileDir}{$this->file}.php”)){
      trigger_error(“Unable to read file contents”,E_USER_WARNING);
    }
    return $content;
  }
}

As seen above, I’ve included a couple of “trigger_error()” functions, right at the places where the class could raise potential errors. According to this rewritten class, a file reader object might be instantiated like this:

// instantiate FileReader object
$fr=new FileReader(‘inexistent_file’);
// echo file content
echo $fr->getContent();

And the resulting output would be as follows:

Notice: File inexistent_file not found in path/to/file
Warning: file_get_contents(fileDir/inexistent_file.php): failed to open stream: No such file or directory in path/to/file
Notice: Unable to read file contents in path/to/file

In this case, the “trigger_error()” function will display some notices and warnings when a specific error has occurred, but in all cases the execution of the program won’t be stopped, since I passed into the function a non-fatal error flag (E_USER_WARNING). As you may have guessed, this error mechanism isn’t very useful when used alone. After all, what’s the point of having a bunch of non-fatal errors, if they’re not processed in a more helpful way?

The real power of the “trigger_error()” function is unleashed when used in conjunction with the “set_error_handler()” function. As you probably know, this function allows us to specify the name of an error handling function, and whenever an error is triggered, program flow will be moved to the specified function.

Certainly, the “trigger_error()/set_error_handler()” combination is very handy for delegating error handling toward a delineated section within an application. To demonstrate its functionality, I’ll rewrite the sample class, this time by specifying a callback function for “set_error_handler()”. Take a look:

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    if(!file_exists(“{$this->fileDir}{$file}.php”)){
      trigger_error(‘File ‘.$file.’ not found’,E_USER_WARNING);
    }
    $this->file=$file;
  }
  function getContent(){
    if(!$content=file_get_contents(“{$this->fileDir}{$this->file}.php”)){
      trigger_error(“Unable to read file contents”,E_USER_WARNING);
    }
    return $content;
  }
}
// define error handling function

function fileErrorHandler($errnum,$errmsg,$file,$lineno){
  if($errnum==E_USER_WARNING){
    echo ‘Error: ‘.$errmsg.'<br />File: ‘.$file.'<br />Line: ‘.$lineno;
    exit();
  }
}

As shown above, I’ve defined the “fileErrorHandler()” function, in order to trap raised errors, and incidentally obtain more specific information about the error that occurred. In this example, the function has been written to display only information on E_USER_WARNING errors, by displaying the message passed in through each “trigger_error()” function, along with the filename and line number at which the error originally occurred. With such a useful error handler, let’s see the output for the improved version of the sample script:

// define error handling function
set_error_handler(‘fileErrorHandler’);
// instantiate FileReader object
$fr=new FileReader(‘inexistent_file’);
// echo file content
echo $fr->getContent();

Error: File inexistent_file not found
File: path/to/file/exception.php
Line: 6

Now, things are more interesting. Notice how program flow was transferred to the “fileErrorHandler()” function, when the first “trigger_error()” function raised an error condition. Additionally, I received slightly more detailed information on the error itself, since the script’s output included the type of error, file and line number where the error took place. This alone gives us a considerable improvement on setting up error handlers, because by defining a callback function, it’s possible to build in a centralized error handling mechanism and liberate application code from manipulating potentially conflictive conditions.

In most cases, the “trigger_error()”/set_error_handler()” combination can be successfully implemented, in order to work either with procedural programs or with object-based applications. Particularly in object-oriented environments, one common approach consists of developing a class (or a set of classes), which are responsible for handling all the errors raised during the execution of an program.

So, taking into account that object-based error manipulation is relevant during the development of an application, it’s worthwhile to take a brief look at the popular PEAR error object, so you can have a clear idea of how it works with the previous “FileReader” class.

{mospagebreak title=The PEAR way: looking at the PEAR_Error object}

In PHP 4 object-oriented scenarios, one of the most popular approaches for handling errors is the PEAR_Error object. While not all developers feel comfortable working with PEAR packages, admittedly it’s a very strong framework that can be used in numerous applications. Specifically, the PEAR_Error object is extremely useful for handling errors, and certainly provides a lot of information that you might need. Let’s have a look at its methods:

- PEAR::getMessage(): returns the error message.
– PEAR::getType(): returns the PEAR_Error subtype.
– PEAR::getUserInfo(): returns additional information on the error and the context where it took place
– PEAR::getCode(): return the error code. Eventually, this method might return no values.

Having described the corresponding object methods, the next step will consist of modifying the sample class, so it can return a PEAR_Error object, instead of using the “trigger_error()” function:

// include PEAR library
require_once(“PEAR.php”);

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    if(!file_exists(“{$this->fileDir}{$file}.php”)){
      return PEAR::RaiseError(‘File ‘.$file. ‘ not found’);
    }
    $this->file=$file;
  }
  function getContent(){
    if(!$content=file_get_contents(“{$this->fileDir}{$this->file}.php”)){
      return PEAR::RaiseError(‘Unable to read file contents’);
    }
    return $content;
  }
}

As you can see, now the above class returns a PEAR_Error object when things go wrong. Given the existence of this object, I’m able to call one of its methods, as follows:


$fr=new FileReader(‘inexistent_file’);
echo $fr->getContent();
if (PEAR::isError($fr)) {
    echo $fr->getMessage().”n”;
    exit();
}

The above example demonstrates how to check for the existence of an error object, and accordingly call its “getMessage()” method. Evidently, this method provides much more flexibility and allows you to obtain specific information on both the nature of the error and the context in which it took place.

Of course, this is only a introductory example, so if you feel curious about PEAR, visit its site (http://pear.php.net/) and browse the numerous packages available for downloading.

Having scratched the surface of PEAR_Error objects, let’s leap forward and analyze the last method for handling program failures, in this case by utilizing Boolean flags.

{mospagebreak title=True and false: handling errors with Boolean flags}

The last error handling method we’ll review here is perhaps the most ancient. Boolean flags have been used from the very beginning of many programming languages, and PHP isn’t an exception. While they’re quite easy to implement, the major drawback is that they’re not very informative about the error that occurred and its context. Here’s a crude (and rather inefficient) implementation of the “FileReader” class, which uses Boolean flags:

class FileReader{
  var $file;
  var $fileDir=’fileDir/';
  function FileReader($file){
    if(!@file_exists(“{$this->fileDir}{$file}.php”)){
      return false;
    }
    $this->file=$file;
  }
  function getContent(){
    if(!@$content=file_get_contents(“{$this->fileDir}{$this->file}.php”)){
      return false;
    }
    return $content;
  }
}

Considering the definition for the above example, class errors might be handled as follows:

$fr=new FileReader(‘inexistent_file’);
if(!$fr->getContent()){
  die(‘Unable to read file contents’);
}
else{
  echo $fr->getContent();
}

 

In the example, I’ve deliberately used the “@” error suppression operator, in order to avoid the complaints of the PHP interpreter and return a false value (or 0 or –1) when a failure happens. At first glance, you can see the inefficiency of this method, as well as its limited flexibility. However, this approach has proven to be quite successful in procedural applications, or when client code is capable of handling simple errors without overly polluting the whole application.

At this point, I’ve explored the pros and cons of common error handling approaches in PHP 4. Probably you’ll want to add a few more methods to my generic list, but in general terms, this is what you’ll need to use in most cases. Definitely, in large web applications, a set of error manipulating classes is preferred, so you can handle errors through a centralized point. However, the “trigger_error()/set_error_handler()” combination may suit the needs of small projects, so it’s worth considering.

To wrap up

In this first tutorial, I’ve hopefully covered the most common techniques for handling failures within PHP 4 applications. Over the second (and last part) of this series, I’ll be focusing attention on exceptions in PHP 5. As you’ll see, exceptions provide a powerful mechanism for handling errors through a centralized point, and offer a nice level of information on raised errors and their context. Want to know more? You’ll have to wait for the last part!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan