Archive

Posts Tagged ‘debug’

PHP Error Handling

January 5th, 2009
Comments Off

For many developers, error handling is somewhat of a myth. They’ve heard about it but with pressing deadlines and management ignorance they are often not given ample opportunity to learn about, let alone implement, proper error handling and debugging techniques.

So, like many things, there are many ways to skin this cat. When working with debugging and error handling, I usually keep the following things in mind:

  • How to trap errors and debug messages
  • How to collect messages
  • How to output messages without disrupting the display
  • How to integrate throughout entire application

One of the most important things to keep in mind with debugging is that OOP is your friend. I won’t get into the pros and cons of OOP here, but just mention that keeping things in classes allows you to abstract your debugging, handle it cleanly and keep it specific to the needs of the class. With this in mind, my following recommendations will be based on this premise.

How to Trap Errors and Debug Messages

Trapping code problems is relatively straightforward. You want to do some kind of test or comparison to determine if there is a problem. Then you determine how to get the message that adequately explains the problem and make it available to the rest of your program. Sometimes a simple if/else block will do the trick to test values that would not otherwise error out, but may need to be set for certain logic to function properly. PHP 5+ provides exception handling using try/catch which is very useful for catching errors that would normally kill your script, allowing you to then handle it accordingly and capture the error message. For example:

1
2
3
4
5
6
7
8
9
10
try
{
    file('my_file.txt');
}
catch(Exception $e)
{
    $error = $e;

    // do something here to compensate for the error
}

You can also create your own exception class that allows you to automate specific actions when certain errrors occur, like logging to a file, emailing the admin, etc.. You can find more information about this at http://www.php.net/manual/en/language.exceptions.php

How to Collect Messages

The first thing you’ll want to do is determine a standard method of collecting messages that you can use in all your applications and classes. You can either write a separate class to do this and extend it in your other classes, or you can create methods within each class that handle things specific to the classes needs. In my example, I collect the messages local to the class.

You can do the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class My_Class
{
    private $last_message = '';
    private $message_array = array();
    private $error_array = array();
    private $debug = false;

    function __contruct($debug)
    {
        $this->debug = $debug;
    }

    private function add_Message($message)
    {
        $this->last_message = $message;
        $this->message_array[] = $message;

        return true;
    }

    private function add_Error($error)
    {
        if($this->debug)
        {
            $this->error_array[] = $error;
        }

        return true;
    }

    public function get_Last_Message()
    {
        return $this->last_message;
    }

    public function get_Message_Array()
    {
        return $this->message_array;
    }

    public function get_Error_Array()
    {
        return $this->error_array();
    }

    public function another_Method()
    {
        // some code goes here
       
        if($problem_found)
        {
            $this->add_Message('This did not work.');
            $this->add_Error('Very complex error for only me to see.');
        }

        // continue method
    }

    public function yet_Another_Method()
    {
        // some code goes here

        try
        {
            // some code that could fail
        }
        catch(Exception $e)
        {
            $this->add_Error('Another very complex error message. ' . $e);
        }
    }
}

This allows you to add a set of methods to a class that help to control messaging as needed. The methods add_Message() and add_Error() are always called if there is a problem, however, error messages are only collected if $debug is passed in as ‘true’ into the constructor. This allows your user to see friendly messages and react as needed, but keeps horrid errors from displaying all over the screen.

Implementation of the class would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$debug = true;

$my_instance = new My_Class($debug);
$my_instance->another_Method();
$my_instance->yet_Another_Method();

// imporant message for user to see
echo $my_instance->get_Last_Message();

// if you need to show the user the entire list of user friendly messages
echo implode('<br />', $my_instance->get_Message_Array());

// output debug and error info and set to string to be handled later
if($debug)
{
    $msg_output = implode('<br />', $my_instance->get_Error_Array());
}

This example, however, is somewhat limiting as it only collects debug data within the class its self. This may be useful for a really low-level class like a database abstraction layer or some other core application class where you cannot guarantee that assets like a database connection or session will be available to do more advanced debugging logging or output. In this scenario, you can abstract your debug collection methods to their own class or have them present in each class and build methods to pass the debug around so it will “bubble to the top” of your application where you can display it and make other logical decisions.

In cases where you are dealing with more advanced classes or you know that a database connection and/or session is available, you have many other options. I use the method above for my core classes, otherwise I use a session and database dependent static class that allows me to make all kinds of debug calls throughout my application. Because they can be stored in the session, and optionally the database, I can access them for display when needed but also track recurring issues across sessions. Combined with custom exception handlers, I am also able to respond to different levels of errors appropriately and send notifications as needed.

How to Output Messages Without Disrupting the Display

Now that you can trap the errors and collect them, you need to properly output them so that they work well with your display elements. Perhaps you only want to show the user the user friendly messages and output actual errors elsewhere if you are in debug mode. I usually do two things to accomplish this properly:

  • Never echo or print ANYTHING unless it is a method or class that outputs something for display.
  • Collect the display content until all necessary logic has been processed and it is safe to determine whether or not it should be displayed.

Doing these two things alone, can make your applications operate much smoother. Here’s two examples: a good and bad way to display page content.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// GOOD WAY
$html = '';

$html .= '
    This is some page HTML and content.
'
;

$html .= '
    This is more page content.
'
;

// processing is done, echo content
echo $html;



// BAD WAY
echo 'This is some page HTML and content.';

echo 'This is more page content.';

In the BAD WAY, if an error happens between the two echos, it’s too late to properly respond. Using the GOOD WAY, if an error happens, the user display can be changed or even redirected to a new page before anything is displayed to the user. Something else to keep in mind is that if you are coding a display method that is used somewhere deep in your program, you may want to consider returning a string rather than echoing out at the end of the method. This way you can still give control to the top level display methods and echo it out when you are ready.

How to Integrate Throughout the Entire Application

Now you are capturing debug and error messages, you have them integrated into your class, and you are outputting the info at the right time, however, your application is probably more than one class, so how do you integrate this into a large application?

If all of your classes are handling errors and messages like the examples above, you can pass the arrays of messages up through the class hierarchy and merge arrays of messages, so that the final display class can handle them properly. It’s ideal to also pass the $debug parameter down into all your classes so that as they extend or instantiate each other, everything has the same debug mode, either on or off. Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class New_Class
{
    private $last_message = '';
    private $message_array = array();
    private $error_array = array();
    private $debug = false;

    function __contruct($debug)
    {
        $this->debug = $debug;
    }

    public function some_Method()
    {
        // some code goes here
       
        // instantiate needed class with debug mode from this class    
        $m_class = new My_Class($this->debug);
        $m_class->another_Method();

        // collect messages and errors from $m_class
        $this->message_array = array_merge($this->message_array, $m_class->get_Message_Array());   
        $this->error_array = array_merge($this-> error_array, $m_class->get_Error_Array());

        // continue method
    }

    private function add_Message($message)
    {
        $this->last_message = $message;
        $this->message_array[] = $message;

        return true;
    }

    private function add_Error($error)
    {
        if($this->debug)
        {
            $this->error_array[] = $error;
        }

        return true;
    }

    public function get_Last_Message()
    {
        return $this->last_message;
    }

    public function get_Message_Array()
    {
        return $this->message_array;
    }

    public function get_Error_Array()
    {
        return $this->error_array();
    }

}

Obviously, there are several ways to handle these kinds of things. As long as you are consistent with all your code and provide a simple way for you to capture errors, you’ll have a great start… and your process will grow and mature with your application requirements. These concepts only scratch the surface, as they can be abstracted into a very dynamic and robust debugging framework with a lot of flexibility… but that is a topic for another time. Regardless of how you do it, if you put some good thought into it, you’ll save yourself a lot of time and headache down the road.

Development, PHP , , , ,



Sponsored Links



agile ajax black hat Cake PHP centering clifford stoll css cuckoo's egg energy energy drinks espionage flash Flex hacker jquery modular MVC objects optimization performance PHP script timer smarty smarty templates stylesheet up-time uptime variable scope web 2.0 Zend Framework