Debug PEAR Based Scripts Easier

Error handling in PEAR can be used to make error messages on your development machine more verbose, while keeping them short for your visitors without much hassle.

When you develop some code on your machine you usually want all information on the errors you get.

Contrary to that you don't want to reveal all this info to the everyday website visitor. Besides the fact that they usually won't understand it there are people who just wait to see something like that and get inside information that may make your site vulnerable to attacks.

The usual way to do it

You can echo out variables or use print_r for structures like arrays. The problem with that is you have to delete all this code when you update your site and next time when something fails write it again.

How PEAR changed things

PEAR code has a simple yet very useful way to pass errors - through error objects that are instantiated when something fails. If you have looked at the example code from the PEAR manual you've already seen how to use that when a database query fails for example. The example shows:

if (DB::isError($result)) {
    die ($result->getMessage());
}

The getMessage() method returns a short message describing the error, like DB Error: syntax error for example.

Surely this can help but usually you'll want to see the query which caused the error, the old way to do that was to start looking in the sources until you find the piece of code which cause the error and then echo out the query.

What else can be displayed

When the PEAR_Error object is instantiated the parameters it takes are:

  • The message mentioned above
  • Error code
  • PEAR error mode
  • Options
  • Developer info

The developer info contains the failed query along with the error message from the database server. Example:

SLECT * FROM mytable
[nativecode=1064 ** You have an error in your SQL syntax near
'SLECT * FROM mytable' at line 1]

This info can be fetched by the getUserinfo() method but again you go into changing code just to find a failing query.

How do I automate this

You are already displaying messages with the getMessage() method so you need just to change things on your side only to get the user info too.

To accomplish this you need to modify the getMessage() method of the PEAR_Error class. It is defined in the source as:

    function getMessage()
    {
        return ($this->error_message_prefix . $this->message);
    }

This can be found in the PEAR.php file in your PHP extensions directory, usually /usr/local/lib/php/ on Unix. Search it and then replace this code with:

    function getMessage()
    {
        return ($this->error_message_prefix . $this->message .
            '<br />' . $this->userinfo);
    }

The next time a query fails you will see it displayed along with the almost useless default message.

It can be even easier

With the PEAR error handling you can even get rid of all that manual checks whether the query failed by setting an appropriate error mode. The default mode called PEAR_ERROR_RETURN doesn't do anything but just quit the function that triggered the error. If you want to change the default for all PEAR objects you just add PEAR::setErrorHandling(mode); to the top of your code (after PEAR.php is included but before any PEAR object is created).

The mode can be PEAR_ERROR_DIE if you want the same messages as from the getMessage method or you can define your own custom function and use it with PEAR_ERROR_CALLBACK like PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'my_function');. Your function accepts an error object which has properties like code, message and userinfo. An example function follows.

function handlePearError($error) {
	echo "$error->message<br />n",
		$error->userinfo;
	exit;
}

If you want to use it on a public server just remove the line which displays $error->userinfo.

If you need to temporarily set the error handling for an object you can do $db->pushErrorHandling(mode); and after you're done restore the previous setting with $db->popErrorHandling();, assuming that your object is called $db.

Comments

thanks for (push|pop)ErrorHandling

thanks for the tip about pushErrorHandling() and popErrorHandling(). These handy little tools don't seem to be documented at http://pear.php.net/

PEAR Error Insights

Thanks for writing up what you have
learned about PEAR error handling. The
PEAR site makes quite an ado about this
feature, yet lacks concrete examples
that provide real world benifits.
After I found how good the feedback is
that can be obtained, while trying to
figure out what was wrong with a QuickForm to DB's autoexecute(), in
seconds I had solved the programming
problem. Then I went in search of
information.
That is when I found you site and some
extra nuggets of wisdom to tuck away.
Thanks...
Jim Tom Polk