【问题标题】:How to catch undefined functions with set_error_handler in PHP如何在 PHP 中使用 set_error_handler 捕获未定义的函数
【发布时间】:2008-08-31 03:57:29
【问题描述】:

我正在飞跃:我的 PHP 脚本将全部失败!

至少,这是我所希望的……`

我不想(实际上)包装try...catch 语句中的每一行,所以我认为我最好的选择是为我的文件的开头制作一个自定义错误处理程序。

我正在练习页面上对其进行测试:

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);

这工作正常,返回:

抱歉,第 17 行出现错误。导致 错误提示未定义变量:imAFakeVariable。

但是,此设置不适用于未定义的函数。

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();

这会返回:

致命错误:调用未定义函数:imafakefunction() in /Library/WebServer/Documents/experimental/errorhandle.php 第 17 行

为什么我的自定义错误处理程序没有捕获未定义的函数?这会导致其他问题吗?

【问题讨论】:

    标签: php


    【解决方案1】:

    我猜你也需要使用register_shutdown_function

    例如:

     register_shutdown_function( array( $this, 'customError' ));.
    
       function customError() 
       {
    
         $arrStrErrorInfo = error_get_last();
    
         print_r( $arrStrErrorInfo );
    
       }
    

    【讨论】:

      【解决方案2】:

      set_error_handler 旨在处理具有以下代码的错误:E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE。这是因为set_error_handler 是一种报告user 错误函数trigger_error 抛出的错误的方法。

      但是,我确实在手册中找到了可能对您有所帮助的评论:

      “以下错误类型无法使用用户定义的函数处理:E_ERRORE_PARSEE_CORE_ERRORE_CORE_WARNINGE_COMPILE_ERRORE_COMPILE_WARNING 和大部分 E_STRICT 在调用 set_error_handler() 的文件。”

      这并不完全正确。 set_error_handler() 无法处理它们,但ob_start() 至少可以处理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();
      
      ?>
      

      确实,尽管这些错误应该在文件中静默报告,例如。希望您的项目中不会有很多E_PARSE 错误! :-)

      至于一般错误报告,请坚持使用异常(我发现将它们与我的 MVC 系统结合起来很有帮助)。您可以构建一个非常通用的异常来通过按钮提供选项并添加大量描述以让用户知道出了什么问题。

      【讨论】:

        【解决方案3】:

        我一直在玩错误处理一段时间,它似乎在大多数情况下都有效。

        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" );
        }
        

        现在我有一个问题,如果内存耗尽,它不会每次都报告它。似乎这取决于使用了多少内存。 我做了一个脚本来无限循环加载一个大文件(需要大约 6.6M 的内存)。 设置1:

        ini_set('memory_limit', '296M');
        
        fatalHandlerInit("testing");
        
        $file[] = file("large file"); // copy paste a bunch of times
        

        在这种情况下,我收到要报告的错误,它在 45 个文件加载时死掉。

        Setup2 - 相同但更改: ini_set('memory_limit', '299M');

        这次我没有收到错误,它甚至没有调用我的自定义错误函数。脚本死在同一行。

        有人知道为什么以及如何解决这个问题吗?

        【讨论】:

          【解决方案4】:

          来自documentation(强调添加):

          以下错误类型无法使用用户定义的函数进行处理:E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING,以及在调用 set_error_handler() 的文件中引发的大部分 E_STRICT。

          调用未定义的函数会触发 E_ERROR,因此错误回调(或异常处理程序)无法处理它。您所能做的就是将 error_reporting 设置为 0。

          PS,如果您正在滚动自己的错误处理程序,则应注意正确处理 @ 运算符。来自文档(强调添加):

          请务必记住,标准的 PHP 错误处理程序已被完全绕过。 error_reporting() 设置将不起作用,并且无论如何都会调用您的错误处理程序 - 但是您仍然能够读取 error_reporting 的当前值并采取适当的行动。 需要特别注意的是,如果导致错误的语句被 @error-control 操作符前置,则该值将为 0。

          【讨论】:

            【解决方案5】:

            为什么我的自定义错误处理程序没有捕获未定义的函数?这会导致其他问题吗?

            我猜想,未定义的函数错误通过与其他错误类型不同的执行路径传播。也许 PHP 设计者可以告诉你更多,但我怀疑 PHP 是否以任何方式设计。

            如果您希望脚本在编写 PHP 风格的同时优雅地失败,请尝试将整个页面放在一个函数中,然后在 try..catch 块中调用它。

            【讨论】:

              【解决方案6】:

              当我面临类似问题时,我今天发现了非常有趣的事情。如果您使用以下内容 - 它将使用您的自定义错误处理程序函数/方法捕获错误:

              ini_set('display_errors', 'Off');
              error_reporting(-1);
              
              set_error_handler(array("Cmd\Exception\Handler", "getError"), -1 & ~E_NOTICE & ~E_USER_NOTICE);
              

              通过将 'display_errors' 设置为 'Off',您仍然可以使用处理程序捕获它们。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-06-27
                • 2017-05-22
                • 1970-01-01
                • 2022-01-24
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多