error_get_last()和自定义错误处理程序

时间:2011-12-14 12:12:44

标签: php error-handling

odbc_errormsg 不会以odbc_execute的方式报告错误消息。它只是抛出一个警告。所以我被迫写了一个hack来通过error_get_last来解析错误信息。

我正在使用set_error_handlererror_get_last会返回NULL,除非我要么:

  1. 禁用我的错误处理程序,

  2. 或让它返回FALSE

  3. 我认为这是由于PHP的内置错误处理程序负责将错误详细信息存储在某处,以便以后检索它们。

    有没有办法在我的自定义错误处理程序中模拟此类行为,以便error_get_last()可以正常使用?

    请注意我已经知道几种方法可以随时检索错误信息。我的问题是如何使error_get_last可用。


    更新:我想我最好发布一些代码。

    PHP有error_get_last(),允许执行此操作:

    @fopen('xxx');
    var_dump( error_get_last() );
    

    ......得到这个:

    array(4) {
      ["type"]=>
      int(2)
      ["message"]=>
      string(46) "fopen() expects at least 2 parameters, 1 given"
      ["file"]=>
      string(69) "C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php"
      ["line"]=>
      int(3)
    }
    

    如果替换内置错误处理程序,则会中断:

    function custom_error_handler($errno, $errstr, $errfile, $errline){
        $ignore = ($errno & error_reporting()) == 0;
        if(!$ignore){
            echo "[Error happened: $errstr]\n";
        }
        return TRUE;
    }
    set_error_handler('custom_error_handler');
    
    @fopen('xxx');
    var_dump( error_get_last() ); // NULL
    

    如果你保留两个错误处理程序......

    function custom_error_handler($errno, $errstr, $errfile, $errline){
        $ignore = ($errno & error_reporting()) == 0;
        if(!$ignore){
            echo "[Error happened: $errstr]\n";
        }
        return FALSE;
    }
    set_error_handler('custom_error_handler');
    
    error_reporting(E_ALL);
    echo $foo;
    

    ......你有副作用:

    [Error happened: Undefined variable: foo]
    
    Notice: Undefined variable: foo in C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php on line 15
    
    Call Stack:
        0.0004     329720   1. {main}() C:\Documents and Settings\ALVARO.GONZALEZ\Mis documentos\tmp\test.php:0
    

    ......而不只是:

    [Error happened: Undefined variable: foo]
    

    我希望我的自定义错误处理程序能够与error_get_last正确连接。我希望error_get_last能正常工作。

2 个答案:

答案 0 :(得分:6)

是的,这是一个奇怪的解决方案,但我认为它将适合您的目的。

经过一段时间的游戏,我发现了这个:

function my_error_handler ($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {

  // Handle the error here

  @trigger_error($errstr);
  return TRUE;

}

// Just to make sure PHP is not outputting anything
error_reporting(-1);
ini_set('display_errors',1);

set_error_handler('my_error_handler');

// An E_USR error...
trigger_error('Some error');
var_dump(error_get_last());

// ...and a native one
$key = count();
var_dump(error_get_last());

结果如下:

array(4) {
  ["type"]=>
  int(1024)
  ["message"]=>
  string(10) "Some error"
  ["file"]=>
  string(69) "C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test.php"
  ["line"]=>
  int(7)
}
array(4) {
  ["type"]=>
  int(1024)
  ["message"]=>
  string(45) "count() expects at least 1 parameter, 0 given"
  ["file"]=>
  string(69) "C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test.php"
  ["line"]=>
  int(7)
}

从错误处理程序中调用@trigger_error(),而不是返回FALSE,导致error_get_last()返回NULL以外的内容,但因为错误被{{ 1}},PHP不输出任何内容。似乎为了避免无限递归,在注册的错误处理函数中调用@不会调用错误处理程序 - 这对我们有利。

显然,错误代码已被修改,但如果需要,您可以将其转换为相关的trigger_error()代码 - 但我怀疑您真正想要的是字符串值,此方法允许您获取。遗憾的是,您还丢失了行号和文件信息 - 尽管您可以通过在错误处理程序中执行涉及堆栈跟踪的操作来解决此问题,或者至少将其包含在传递的参数的字符串中。

这是一个可怕的,可怕的,可怕的黑客攻击 - 但由于没有正式批准的方法,黑客本质上就是你所要求的。

答案 1 :(得分:0)

您可以更改自定义错误处理程序以返回false,只是在忽略错误时(使用@ -operator)。

function custom_error_handler($errno, $errstr, $errfile, $errline){
    $ignore = ($errno & error_reporting()) == 0;
    if ($ignore) {
        return FALSE;
    }
    echo "[Error happened: $errstr]\n";
    return TRUE;
}