dougao7801 2014-12-01 22:23
浏览 26

如何在PHP中捕获所有错误?

I've found a lot of attempts at all-inclusive error handling implementations, and I figured I might write up a wiki-style to hopefully provide a complete solution that I came up with.

The question is:

"How might one catch, handle, or intercept ALL error types in PHP?"

Now - this might be deemed a 'rewrite' by some - but I don't know that there's been a comprehensive solution proposed.

  • 写回答

3条回答 默认 最新

  • doujin8476 2014-12-01 22:23
    关注

    There are a number of levels of PHP errors, some of these require setting separate error handlers, and in order to catch every error PHP might throw up - you must write something that encompasses all of these 'types' of errors -- startup, 'runtime', and exceptions.

    My solution to catch every ( as far as I can tell ) error that comes down the pipe:

    • A couple of global variables
    • An initialization method
    • 4 'non-OOP' error handler methods
    • An ErrorHandler class with an 'AppendError' method - which is where one might make modifications to how exactly errors are output or not ( in this case, errors are just dumped to the screen in some minimal HTML from this method )

    ...

    // Moved this line to the bottom of the 'file' for usability - 
    // I keep each of the above mentioned 'pieces' in separate files.
    //$ErrorHandler = new ErrorHandler();
    
    $ErrorCallback = "HandleRuntimeError";
    $ExceptionCallback = "HandleException";
    $FatalCallback = "HandleFatalError";
    
    $EnableReporting = true;
    $ErrorLevel = E_ALL;
    
    function InitializeErrors()
    {
        if($GLOBALS["EnableReporting"])
        {
            error_reporting($GLOBALS["ErrorLevel"]);
    
            if( isset($GLOBALS["ErrorCallback"]) && strlen($GLOBALS["ErrorCallback"]) > 0 )
            {
                set_error_handler($GLOBALS["ErrorCallback"]);
    
                // Prevent the PHP engine from displaying runtime errors on its own
                ini_set('display_errors',false);
            }
            else
                ini_set('display_errors',true);
    
            if( isset($GLOBALS["FatalCallback"]) && strlen($GLOBALS["FatalCallback"]) > 0 )
            {
                register_shutdown_function($GLOBALS["FatalCallback"]);
    
                // Prevent the PHP engine from displaying fatal errors on its own
                ini_set('display_startup_errors',false);
            }
            else
                ini_set('display_startup_errors',true);
    
            if( isset($GLOBALS['ExceptionCallback']) && strlen($GLOBALS['ExceptionCallback']) > 0 )
                set_exception_handler($GLOBALS["ExceptionCallback"]);
        }
        else
        {
            ini_set('display_errors',0);
            ini_set('display_startup_errors',0);
            error_reporting(0);
        }
    }
    
    function HandleRuntimeError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null)
    {
        if( isset($GLOBALS['ErrorHandler']))
        {
            //  Pass errors up to the global ErrorHandler to be later inserted into
            // final output at the appropriate time.
            $GLOBALS['ErrorHandler']->AppendError($ErrorLevel,"Runtime Error: " . $ErrorMessage,$ErrorFile,$ErrorLine,$ErrorContext);
    
            return true;
        }
        else
        {
            PrintError($ErrorLevel,$ErrorMessage,$ErrorFile,$ErrorLine,$ErrorContext);
            return true;
        }
    }
    
    function HandleException($Exception)
    {
        if( isset($GLOBALS['ErrorCallback']))
        {
            // Parse and pass exceptions up to the standard error callback.
            $GLOBALS['ErrorCallback']($Exception->getCode(), "Exception: " . $Exception->getMessage(), $Exception->getFile(), $Exception->getLine(), $Exception->getTrace());
    
            return true;
        }
        else
        {       
            PrintError($Exception->getCode(), "Exception: " . $Exception->getMessage(), $Exception->getFile(), $Exception->getLine(), $Exception->getTrace());
            return true;
        }
    }
    
    function HandleFatalError()
    {
        $Error = error_get_last();
    
        // Unset Error Type and Message implies a proper shutdown.
        if( !isset($Error['type']) && !isset($Error['message']))
            exit();
        else if( isset($GLOBALS['ErrorCallback']))
        {
            // Pass fatal errors up to the standard error callback.
            $GLOBALS["ErrorCallback"]($Error['type'], "Fatal Error: " . $Error['message'],$Error['file'],$Error['line']);
    
            return null;
        }
        else
        {
            PrintError($Error['type'], "Fatal Error: " . $Error['message'],$Error['file'],$Error['line']);
            return null;
        }
    }
    
    // In the event that our 'ErrorHandler' class is in fact the generator of the error,
    // we need a plain-Jane method that will still deliver the message.
    function PrintError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null)
    {
        if( class_exists("ErrorHandler"))
            $ErrorTypeString = ErrorHandler::ErrorTypeString($ErrorLevel);
        else
            $ErrorTypeString = "$ErrorLevel";
    
        if( isset($ErrorContext) && !is_array($ErrorContext) && strlen($ErrorContext) > 0 )
            $ErrorContext = str_replace("#", "<br/>
    #", $ErrorContext);
    
        $ReturnValue = "";
        $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">
    ";
    
        $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>
    ";
    
        if( isset($ErrorFile) && strlen($ErrorFile) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>
    ";
    
        if( isset($ErrorLine) && strlen($ErrorLine) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>
    ";
    
        if( isset($ErrorContext) && is_array($ErrorContext))
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>
    ";
        else if( isset($ErrorContext) && strlen($ErrorContext) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>
    ";
    
        $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("
    ","<br/>
    ",$ErrorMessage) . "</span></p>
    ";
    
        $ReturnValue .= "</div>
    ";
    
        echo($ReturnValue);
    }
    
    class ErrorHandler
    {   
        public function AppendError($ErrorLevel,$ErrorMessage,$ErrorFile=null,$ErrorLine=null,$ErrorContext=null)
        {
            // Perhaps evaluate the error level and respond accordingly
            //
            // In the event that this actually gets used, something that might 
            // determine if you're in a production environment or not, or that 
            // determines if you're an admin or not - or something - could belong here.
            // Redirects or response messages accordingly.
            $ErrorTypeString = ErrorHandler::ErrorTypeString($ErrorLevel);
    
            if( isset($ErrorContext) && !is_array($ErrorContext) && strlen($ErrorContext) > 0 )
                $ErrorContext = str_replace("#", "<br/>
    #", $ErrorContext);
    
            $ReturnValue = "";
            $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">
    ";
    
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>
    ";
    
            if( isset($ErrorFile) && strlen($ErrorFile) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>
    ";
    
            if( isset($ErrorLine) && strlen($ErrorLine) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>
    ";
    
            if( isset($ErrorContext) && is_array($ErrorContext))
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>
    ";
            else if( isset($ErrorContext) && strlen($ErrorContext) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>
    ";
    
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("
    ","<br/>
    ",$ErrorMessage) . "</span></p>
    ";
    
            $ReturnValue .= "</div>
    ";
    
            echo($ReturnValue);
        }
    
        public static function ErrorTypeString($ErrorType)
        {
            $ReturnValue = "";
    
            switch( $ErrorType )
            {
                default:
                    $ReturnValue = "E_UNSPECIFIED_ERROR"; 
                    break;
                case E_ERROR: // 1 //
                    $ReturnValue = 'E_ERROR'; 
                    break;
                case E_WARNING: // 2 //
                    $ReturnValue = 'E_WARNING'; 
                    break;
                case E_PARSE: // 4 //
                    $ReturnValue = 'E_PARSE'; 
                    break;
                case E_NOTICE: // 8 //
                    $ReturnValue = 'E_NOTICE'; 
                    break;
                case E_CORE_ERROR: // 16 //
                    $ReturnValue = 'E_CORE_ERROR'; 
                    break;
                case E_CORE_WARNING: // 32 //
                    $ReturnValue = 'E_CORE_WARNING'; 
                    break;
                case E_COMPILE_ERROR: // 64 //
                    $ReturnValue = 'E_COMPILE_ERROR'; 
                    break;
                case E_CORE_WARNING: // 128 //
                    $ReturnValue = 'E_COMPILE_WARNING'; 
                    break;
                case E_USER_ERROR: // 256 //
                    $ReturnValue = 'E_USER_ERROR'; 
                    break;
                case E_USER_WARNING: // 512 //
                    $ReturnValue = 'E_USER_WARNING'; 
                    break;
                case E_USER_NOTICE: // 1024 //
                    $ReturnValue = 'E_USER_NOTICE'; 
                    break;
                case E_STRICT: // 2048 //
                    $ReturnValue = 'E_STRICT';
                    break;
                case E_RECOVERABLE_ERROR: // 4096 //
                    $ReturnValue = 'E_RECOVERABLE_ERROR';
                    break;
                case E_DEPRECATED: // 8192 //
                    $ReturnValue = 'E_DEPRECATED'; 
                    break;
                case E_USER_DEPRECATED: // 16384 //
                    $ReturnValue = 'E_USER_DEPRECATED'; 
                    break;
            }
    
            return $ReturnValue;
        }
    }
    
    $ErrorHandler = new ErrorHandler();
    

    Now - code out of the way...

    To implement this, it's as simple as including this file, and executing the 'InitializeErrors' method. Beyond this, it's up to you what you want to Do with the errors; this is simply a wrapper for every error that PHP might generate - and to make changes to how any given error is handled, it's basically as simple as evaluating it in the 'AppendError' method and responding accordingly.

    -- I should note - I implemented return values for reasons I cannot explain, and I should review my own work on that front - but I'm not terribly sure it has any bearing on the result.

    评论

报告相同问题?

悬赏问题

  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探