How to catch undefined functions with set_error_handler in PHP

后端 未结 6 495
一整个雨季
一整个雨季 2021-02-05 19:47

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 i

相关标签:
6条回答
  • 2021-02-05 20:42

    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.

    0 讨论(0)
  • 2021-02-05 20:46

    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?

    0 讨论(0)
  • 2021-02-05 20:46

    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.

    0 讨论(0)
  • 2021-02-05 20:47

    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.

    0 讨论(0)
  • 2021-02-05 20:47

    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 );
    
       }
    
    0 讨论(0)
  • 2021-02-05 20:47

    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.

    0 讨论(0)
提交回复
热议问题