Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error handling in PHP

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?

like image 693
VirtuosiMedia Avatar asked Sep 25 '08 16:09

VirtuosiMedia


People also ask

What is PHP 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.

What is error handling and its types?

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.

What is exception and error in PHP?

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.


4 Answers

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:

  • Create a "crash" table in your database and a set of wrapper classes for reporting errors. I'd recommend setting categories for the crashes ("blocking", "security", "PHP error/warning" (vs exception), etc).
  • In all of your error handling code, make sure to record the error. Doing this consistently depends on how well you built the API (above step) - it should be trivial to record crashes if done right.

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

  • send an email to the admin, AND/OR
  • record the details of the crash to a plain text file

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.

like image 121
Alex Weinstein Avatar answered Oct 08 '22 07:10

Alex Weinstein


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());
}
like image 35
troelskn Avatar answered Oct 08 '22 07:10

troelskn


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();

?>
like image 3
andy.gurin Avatar answered Oct 08 '22 09:10

andy.gurin


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 />');
like image 2
Teifion Avatar answered Oct 08 '22 08:10

Teifion