13

I'm taking the leap: my PHP scripts will ALL fail gracefully!

At least, that's what I'm hoping for...`

I don't want to wrap (practically) every single line in try...catch statements, so I think my best bet is to make a custom error handler for the beginning of my files.

I'm testing it out on a practice page:

function customError($level,$message,$file,$line,$context) {
    echo "Sorry, an error has occured on line $line.<br />";
    echo "The function that caused the error says $message.<br />";
    die();
}

set_error_handler("customError");

echo($imAFakeVariable);

This works fine, returning:

Sorry, an error has occurred on line 17. The function that caused the error says Undefined variable: imAFakeVariable.

However, this setup doesn't work for undefined functions.

function customError($level,$message,$file,$line,$context) {
    echo "Sorry, an error has occured on line $line.<br />";
    echo "The function that caused the error says $message.<br />";
    die();
}

set_error_handler("customError");

imAFakeFunction();

This returns:

Fatal error: Call to undefined function: imafakefunction() in /Library/WebServer/Documents/experimental/errorhandle.php on line 17

Why isn't my custom error handler catching undefined functions? Are there other problems that this will cause?

7 Answers 7

15

set_error_handler is designed to handle errors with codes of: E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE. This is because set_error_handler is meant to be a method of reporting errors thrown by the user error function trigger_error.

However, I did find this comment in the manual that may help you:

"The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called."

This is not exactly true. set_error_handler() can't handle them, but ob_start() can handle at least E_ERROR.

<?php

function error_handler($output)
{
    $error = error_get_last();
    $output = "";
    foreach ($error as $info => $string)
        $output .= "{$info}: {$string}\n";
    return $output;
}

ob_start('error_handler');

will_this_undefined_function_raise_an_error();

?>

Really though these errors should be silently reported in a file, for example. Hopefully you won't have many E_PARSE errors in your project! :-)

As for general error reporting, stick with Exceptions (I find it helpful to make them tie in with my MVC system). You can build a pretty versatile Exception to provide options via buttons and add plenty of description to let the user know what's wrong.

Sign up to request clarification or add additional context in comments.

Comments

8

I guess you needs to use register_shutdown_function also

For example:

 register_shutdown_function( array( $this, 'customError' ));.

   function customError() 
   {

     $arrStrErrorInfo = error_get_last();

     print_r( $arrStrErrorInfo );

   }

Comments

2

From the documentation (emphasis added):

The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.

Calling undefined functions triggers an E_ERROR, thus it can not be handled by the error callback (or by exception handlers for that matter). All that you can do is set error_reporting to 0.

PS, if you are rolling your own error handler, you should take care to handle correctly the @ operator. From the documentation (emphasis added):

It is important to remember that the standard PHP error handler is completely bypassed. error_reporting() settings will have no effect and your error handler will be called regardless - however you are still able to read the current value of error_reporting and act appropriately. Of particular note is that this value will be 0 if the statement that caused the error was prepended by the @ error-control operator.

Comments

1

Why isn't my custom error handler catching undefinedd functions? Are there other problems that this will cause?

At a guess, I'd say that undefined function errors travel through a different execution path than other error types. Perhaps the PHP designers could tell you more, except I doubt PHP is in any way designed.

If you'd like your scripts to fail gracefully while still writing them PHP-style, try putting the entire page in a function and then call it within a try..catch block.

Comments

1

I've been playing around with error handling for some time and it seems like it works for the most part.

function fatalHandler() {
    global $fatalHandlerError, $fatalHandlerTitle;

    $fatalHandlerError = error_get_last();

    if( $fatalHandlerError !== null ) {

        print($fatalHandlerTitle="{$fatalHandlerTitle} | ".join(" | ", $fatalHandlerError).
                (preg_match("/memory/i", $fatalHandlerError["message"]) ? " | Mem: limit ".ini_get('memory_limit')." / peak ".round(memory_get_peak_usage(true)/(1024*1024))."M" : "")."\n".
                        "GET: ".var_export($_GET,1)."\n".
                        "POST: ".var_export($_POST,1)."\n".
                        "SESSION: ".var_export($_SESSION,1)."\n".
                        "HEADERS: ".var_export(getallheaders(),1));
    }

    return $fatalHandlerTitle;
}

function fatalHandlerInit($title="phpError") {
    global $fatalHandlerError, $fatalHandlerTitle;

    $fatalHandlerTitle = $title;
    $fatalHandlerError = error_get_last();

    set_error_handler( "fatalHandler" );
}

Now I have an issue where if the memory is exhausted, it doesn't report it every time. It seems like it depends on how much memory is being used. I did a script to load a large file (takes ~6.6M of memory) in an infinite loop. Setup1:

ini_set('memory_limit', '296M');

fatalHandlerInit("testing");

$file[] = file("large file"); // copy paste a bunch of times

In this case I get the error to be reports and it dies on 45 file load.

Setup2 - same but change: ini_set('memory_limit', '299M');

This time I don't get an error and it doesn't even call my custom error function. The script dies on the same line.

Does anyone have a clue why and how to go around that?

Comments

0

Very interesting thing that I've discovered today as I was facing the similar problem. If you use the following - it will catch the error with your custom error handler function / method:

ini_set('display_errors', 'Off');
error_reporting(-1);

set_error_handler(array("Cmd\Exception\Handler", "getError"), -1 & ~E_NOTICE & ~E_USER_NOTICE);

By setting 'display_errors' to 'Off' you can catch still catch them with the handler.

Comments

0

At a guess, I'd say that undefined function errors travel through a different execution path than other error types. Perhaps the PHP designers could tell you more, except I doubt PHP is in any way designed.

1 Comment

This does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.