Error Handling for Your PHP Application

How to

However fondly you treat your application, errors happen and they happen often when it is being developed. That’s obvious you want to get all the tracing information during the development stage and something like ‘Application Error’ page if the error occurs on the production.

Everybody knows error handler can be set in PHP through set_error_handler. The same about exceptions for which set_exception_handler is used. But it really works only for user-defined errors and uncaught exceptions. It doesn’t affect any of fatal error for instance. Well, PHP has such stuff as register_shutdown_function to deal with them. We can create ErrorHandler class and subscribe the handlers in the beginning of the script like that:

        register_shutdown_function(array(' ErrorHandler ', 'shutdownHandler'));
        set_error_handler(array(' ErrorHandler ', 'errorHandler'));
        set_exception_handler(array(' ErrorHandler ', 'exceptionHandler'));

However, now any cessation of the program (exit, die, e.t.c) invokes shutdownHandler and we have to know was it demanded exit or abnormal termination. Let’s use a private property _abnormalTermination as a state trigger. We can have shutdown method, which switches the trigger into ‘true’ and stops the program. Then invoked shutdownHandler according to the trigger state omits all the logic for abnormal termination case.

So, let’s have an error collector. It can be just an array. When a warning or notice occurs, errorHandler just appends its tracing information (error message, code, line, file and context) in the collector. To the program completion we going to have the stack of all the system messages encountered during scripts run. In the case of a fatal error or an exception, the program is terminated, but error data is also collected. So we can render the error page including tracing data when it’s development environment.

When the program is completed normally, it ends in shutdownHadler anyway. If error stack is not empty we can display its events on an overlay, for instance. Another options is to log them.

When you’ve it done, you likely notice that it doesn’t really work for exceptions. If the exception is caught once, it doesn’t appear in the handler. Unless you check all the possible exception for any API method call in your controllers. But you do it only for the excepted ones. Others can be caught by application runner try/catch wrapper.

Using Zend Framework you can go further and even without that wrapper:

$front->returnResponse(true);
$response = $front->dispatch();
if ($response->isException()) {
    $exceptions = $response->getException();
    // handle exceptions ...
} else {
    $response->sendHeaders();
    $response->outputBody();
}

Logger

Well, as it’s already said, shutdownHandler is up to let us know when error or uncaught exception happens. It might be delivered as page or overlay, but not always. If it’s XMLHttpRequest, expected response is hardly of html type, but JSON or XML.

However if log event into a file, that’s doesn’t matter. Besides, in the case of FirePHP console that’s really useful and good-looking. The only you need, that is to download the library and follow those examples:

require_once('FirePHPCore/FirePHP.class.php');
$firephp = FirePHP::getInstance(true);
$firephp->log('Plain Message');     
$firephp->info('Info Message');     
$firephp->warn('Warn Message');     
$firephp->error('Error Message');   
$firephp->trace('Trace Label');

Under Zend Framework we are provided with such a nice tool as Zend_Log. So we just add writers to the logger object for the all of output types we wish. For example, here we log into a file and to the FirePHP console.

$logger = new Zend_Log();
$writer1 = new Zend_Log_Writer_Stream('/path/to/first/logfile');
$logger->addWriter($writer1);
$writer2 = new Zend_Log_Writer_Firebug();
$logger->addWriter($writer2);
$logger->err($exception);
$logger->info($message);

Moreover, when the request expects especial data form, we do it using formatters:

$logger = new Zend_Log();
$writer = new Zend_Log_Writer_Stream('/path/to/first/logfile');
$formatter = new Zend_Log_Formatter_Xml();
$writer->setFormatter($formatter);
$logger->addWriter($writer);

Thanks for the enlightenment to Alex