6
\$\begingroup\$

I've tried to catch all exceptions and errors in PHP in a way so that I can deal with them consistently.

This is the code with the exception of the very last bit where I instead pass $e on to a method that outputs an error page as HTML.

// Only let PHP report errors in dev
error_reporting(ENV === 'dev' ? E_ALL : 0);

// Register handler
set_error_handler("error_handler");
set_exception_handler("error_handler");
register_shutdown_function("error_handler");

function error_handler()
{
    // Check for unhandled errors (fatal shutdown)
    $e = error_get_last();

    // If none, check function args (error handler)
    if($e === null)
        $e = func_get_args();

    // Return if no error
    if(empty($e))
        return;

    // "Normalize" exceptions (exception handler)
    if($e[0] instanceof Exception)
    {
        call_user_func_array(__FUNCTION__, array(
            $e[0]->getCode(),
            $e[0]->getMessage(),
            $e[0]->getFile(),
            $e[0]->getLine(),
            $e[0]));
        return;
    }

    // Create with consistent array keys
    $e = array_combine(array('number', 'message', 'file', 'line', 'context'), 
                       array_pad($e, 5, null));

    // Output error page
    var_dump($e);
    exit;
}

I'm wondering if this is a decent way of doing it or if I have missed anything crucial. Any comments?

\$\endgroup\$
2
\$\begingroup\$
  1. I don't think that printing raw errors/data to the users is a good idea:

    var_dump($e);
    

    They (usually) can't fix it, so it doesn't help them. (See #3 here) It might also contain sensitive information which could help attackers.

    Instead of that you should log the errors to a log file, hide the details from the user (don't forget to print a friendly error message) and fix the errors. Your users might not call/mail you when they found a bug. They just simply use one of your competitor's service.

  2. Instead of using the same function for three more or less different purposes:

    set_error_handler("error_handler");
    set_exception_handler("error_handler");
    register_shutdown_function("error_handler");
    

    I'd use three different functions (with proper signatures) which might call a fourth one. It would be cleaner (easier to read, understand and maintain). It would make unnecessary the internal magic with error_get_last(), func_get_args() and instanceof.

  3. // Only let PHP report errors in dev
    error_reporting(ENV === 'dev' ? E_ALL : 0);
    

    It seems to me as a code smell: Test Logic in Production. I'd use php.ini to set this, I guess php.ini is a straightforward place for most of the PHP developers to set this instead of a PHP file.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.