I'm familiar with some of the basics, but what I would like to know more about is when and why error handling (including throwing exceptions) should be used in PHP, especially on a live site or web app. Is it something that can be overused and if so, what does overuse look like? Are there cases where it shouldn't be used? Also, what are some of the common security concerns in regard to error handling?
Error handling in PHP is simple. An error message with filename, line number and a message describing the error is sent to the browser.
Error handling refers to the response and recovery procedures from error conditions present in a software application. In other words, it is the process comprised of anticipation, detection and resolution of application errors, programming errors or communication errors.
An exception is an object that describes an error or unexpected behaviour of a PHP script. Exceptions are thrown by many PHP functions and classes. User defined functions and classes can also throw exceptions. Exceptions are a good way to stop a function when it comes across data that it cannot use.
One thing to add to what was said already is that it's paramount that you record any errors in your web application into a log. This way, as Jeff "Coding Horror" Atwood suggests, you'll know when your users are experiencing trouble with your app (instead of "asking them what's wrong").
To do this, I recommend the following type of infrastructure:
Extra credit: sometimes, your crashes will be database-level crashes: i.e. DB server down, etc. If that's the case, your error logging infrastructure (above) will fail (you can't log the crash to the DB because the log tries to write to the DB). In that case, I would write failover logic in your Crash wrapper class to either
All of this sounds like an overkill, but believe me, this makes a difference in whether your application is accepted as a "stable" or "flaky". That difference comes from the fact that all apps start as flaky/crashing all the time, but those developers that know about all issues with their app have a chance to actually fix it.
Roughly speaking, errors are a legacy in PHP, while exceptions are the modern way to treat errors. The simplest thing then, is to set up an error-handler, that throws an exception. That way all errors are converted to exceptions, and then you can simply deal with one error-handling scheme. The following code will convert errors to exceptions for you:
function exceptions_error_handler($severity, $message, $filename, $lineno) {
if (error_reporting() == 0) {
return;
}
if (error_reporting() & $severity) {
throw new ErrorException($message, 0, $severity, $filename, $lineno);
}
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);
There are a few cases though, where code is specifically designed to work with errors. For example, the schemaValidate
method of DomDocument
raises warnings, when validating a document. If you convert errors to exceptions, it will stop validating after the first failure. Some times this is what you want, but when validating a document, you might actually want all failures. In this case, you can temporarily install an error-handler, that collects the errors. Here's a small snippet, I've used for that purpose:
class errorhandler_LoggingCaller {
protected $errors = array();
function call($callback, $arguments = array()) {
set_error_handler(array($this, "onError"));
$orig_error_reporting = error_reporting(E_ALL);
try {
$result = call_user_func_array($callback, $arguments);
} catch (Exception $ex) {
restore_error_handler();
error_reporting($orig_error_reporting);
throw $ex;
}
restore_error_handler();
error_reporting($orig_error_reporting);
return $result;
}
function onError($severity, $message, $file = null, $line = null) {
$this->errors[] = $message;
}
function getErrors() {
return $this->errors;
}
function hasErrors() {
return count($this->errors) > 0;
}
}
And a use case:
$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
array($doc, 'schemaValidate'),
array($xsd_filename));
if ($validation->hasErrors()) {
var_dump($validation->getErrors());
}
The best practice IMHO is to use the following approach: 1. create an error/exception handler 2. start it upon the app start up 3. handle all your errors from inside there
<?php
class Debug {
public static setAsErrorHandler() {
set_error_handler(array(__CLASS__, '__error_handler'));
}
public static function __error_handler($errcode, $errmsg, $errfile, $errline) {
if (IN DEV) {
print on screen
}
else if (IN PRO) {
log and mail
}
}
}
Debug::setAsErrorHandler();
?>
Unhanded errors stop the script, that alone is a pretty good reason to handle them.
Generally you can use a Try-Catch block to deal with errors
try
{
// Code that may error
}
catch (Exception $e)
{
// Do other stuff if there's an error
}
If you want to stop the error or warning message appearing on the page then you can prefix the call with an @ sign like so.
@mysql_query($query);
With queries however it's generally a good idea to do something like this so you have a better idea of what's going on.
@mysql_query($query)
or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With