【问题标题】:How can I catch ALL errors in PHP?如何捕获 PHP 中的所有错误?
【发布时间】:2015-01-30 01:17:00
【问题描述】:

我在包罗万象的错误处理实现方面发现了很多尝试,我想我可能会写一个 wiki 样式,希望能提供我想出的完整解决方案。

问题是:

“如何捕获、处理或拦截 PHP 中的所有错误类型?”

现在 - 这可能被某些人认为是“重写” - 但我不知道是否提出了一个全面的解决方案。

【问题讨论】:

    标签: php error-handling custom-error-handling


    【解决方案1】:

    您需要三种错误处理程序:

    • set_exception_handler,用于捕获任何其他未捕获的异常。

    • set_error_handler 捕获“标准”PHP 错误。我喜欢先对照error_reporting 检查它是否是应该处理或忽略的错误(我通常会忽略Notices - 可能很糟糕,但这是我的选择),然后抛出ErrorException,让异常处理程序捕获它输出。

    • register_shutdown_functionerror_get_last 结合使用。检查['type'] 的值以查看它是E_ERRORE_PARSE 还是您想要捕获的任何致命错误类型。这些通常绕过set_error_handler,所以在这里抓住它们可以让你抓住它们。同样,我倾向于只抛出一个ErrorException,以便所有错误最终都由同一个异常处理程序处理。

    至于你如何实现这些,这完全取决于你的代码是如何设置的。我通常会使用ob_end_clean() 来清除任何输出,并显示一个漂亮的错误页面,告诉他们错误已被报告。

    【讨论】:

    • 我想是对“问题”的有效答案 - 但为了记录,这里的想法是提供一个实际的实现示例。无论如何都干杯;所有好的信息。
    【解决方案2】:

    有许多级别的 PHP 错误,其中一些需要设置单独的错误处理程序,并且为了捕获 PHP 可能抛出的每个错误 - 您必须编写包含所有这些“类型”错误的内容 -启动、“运行时”和异常。

    我的解决方案是捕获管道中出现的每个(据我所知)错误:

    • 几个全局变量
    • 一种初始化方法
    • 4 种“非 OOP”错误处理方法
    • 带有“AppendError”方法的 ErrorHandler 类 - 可以在其中修改错误的输出方式(在这种情况下,错误只是通过该方法以一些最小的 HTML 转储到屏幕上)李>

    ...

    // 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/>\r\n#", $ErrorContext);
    
        $ReturnValue = "";
        $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">\r\n";
    
        $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>\r\n";
    
        if( isset($ErrorFile) && strlen($ErrorFile) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>\r\n";
    
        if( isset($ErrorLine) && strlen($ErrorLine) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>\r\n";
    
        if( isset($ErrorContext) && is_array($ErrorContext))
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>\r\n";
        else if( isset($ErrorContext) && strlen($ErrorContext) > 0 )
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>\r\n";
    
        $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("\r\n","<br/>\r\n",$ErrorMessage) . "</span></p>\r\n";
    
        $ReturnValue .= "</div>\r\n";
    
        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/>\r\n#", $ErrorContext);
    
            $ReturnValue = "";
            $ReturnValue .= "<div class=\"$ErrorTypeString\" style=\"margin: 10px;\">\r\n";
    
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Error Level:</span> <span class=\"ErrorValue\">$ErrorTypeString</span></p>\r\n";
    
            if( isset($ErrorFile) && strlen($ErrorFile) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">File:</span> <span class=\"ErrorValue\">'$ErrorFile'</span></p>\r\n";
    
            if( isset($ErrorLine) && strlen($ErrorLine) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Line:</span> <span class=\"ErrorValue\">$ErrorLine</span></p>\r\n";
    
            if( isset($ErrorContext) && is_array($ErrorContext))
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">" . var_export($ErrorContext,true) . "</span></p>\r\n";
            else if( isset($ErrorContext) && strlen($ErrorContext) > 0 )
                $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Context:</span><span class=\"ErrorValue\">$ErrorContext</span></p>\r\n";
    
            $ReturnValue .= "<p class=\"ErrorData\"><span class=\"ErrorKey\">Message:</span> <span class=\"ErrorValue\">" . str_replace("\r\n","<br/>\r\n",$ErrorMessage) . "</span></p>\r\n";
    
            $ReturnValue .= "</div>\r\n";
    
            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();
    

    现在 - 代码不碍事...

    要实现这一点,只需包含此文件并执行“InitializeErrors”方法即可。除此之外,您要如何处理错误取决于您;这只是 PHP 可能生成的每个错误的包装器 - 并且要更改任何给定错误的处理方式,它基本上就像在 'AppendError' 方法中评估它并做出相应的响应一样简单。

    -- 我应该注意 - 我实现返回值的原因我无法解释,我应该在这方面回顾我自己的工作 - 但我不太确定它对结果有什么影响。

    【讨论】:

      【解决方案3】:

      在 [phpMyAdmin-4.6.5.2-all-languages] 中的文件 [Config.php] 中可以找到:

      /**
       * Error handler to catch fatal errors when loading configuration
       * file
       *
       *
       * PMA_Config_fatalErrorHandler
       * @return void
       */
      public static function fatalErrorHandler()
      {
          if (!isset($GLOBALS['pma_config_loading'])
              || !$GLOBALS['pma_config_loading']
          ) {
              return;
          }
      
          $error = error_get_last();
          if ($error === null) {
              return;
          }
      
          PMA_fatalError(
              sprintf(
                  'Failed to load phpMyAdmin configuration (%s:%s): %s',
                  Error::relPath($error['file']),
                  $error['line'],
                  $error['message']
              )
          );
      }
      

      就在文件末尾:

      register_shutdown_function(array('PMA\libraries\Config', 'fatalErrorHandler'));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-14
        • 2016-12-07
        • 1970-01-01
        • 2017-07-06
        • 1970-01-01
        • 2011-04-28
        相关资源
        最近更新 更多