English 中文(简体)
如何在PHP中使用set_error_handler捕获未定义的函数
原标题:
  • 时间:2008-08-31 03:57:29
  •  标签:

我正在迈出一步:我的PHP脚本将全部失败!

至少,这是我所希望的`

我不想(实际上)包装<code>中的每一行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);

这很好,返回:

Sorry, an error has occurred on line 17. The function that caused the error says Undefined variable: 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();

这将返回:

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

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

最佳回答

<code>set_error_handler</code>用于处理以下代码的错误:<code>E_USER_error | E_USER_WARNING | E_USER_NOTICE</code>。这是因为set_error_handler是一种报告用户错误函数trigger_error引发的错误的方法。

然而,我确实在手册中发现了这一评论,这可能会对您有所帮助:

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

这并不完全正确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}
";
    return $output;
}

ob_start( error_handler );

will_this_undefined_function_raise_an_error();

?>

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

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

问题回答

我想您还需要使用register_shutdown_function

例如:

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

   function customError() 
   {

     $arrStrErrorInfo = error_get_last();

     print_r( $arrStrErrorInfo );

   }

文档(增加了强调):

以下错误类型不能用用户定义的函数处理: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_reportion的当前值并采取适当的操作特别注意的是,如果导致错误的语句是由@error control运算符预先准备的,则该值将为0

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

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

如果你想让你的脚本在以PHP风格编写时优雅地失败,试着把整个页面放在一个函数中,然后在<code>中调用它。。catch块。

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

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" : "")."
".
                        "GET: ".var_export($_GET,1)."
".
                        "POST: ".var_export($_POST,1)."
".
                        "SESSION: ".var_export($_SESSION,1)."
".
                        "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

在这种情况下,我得到了错误报告,它在45个文件加载时死亡。

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

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

有人知道为什么以及如何绕过这一点吗?

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

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

set_error_handler(array("CmdExceptionHandler", "getError"), -1 & ~E_NOTICE & ~E_USER_NOTICE);

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

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





相关问题