【问题标题】:error_get_last() and custom error handlererror_get_last() 和自定义错误处理程序
【发布时间】:2011-12-14 12:12:44
【问题描述】:

odbc_errormsg 不会以应有的方式报告来自odbc_execute 的错误消息。它只是发出警告。所以我不得不写一个hack来通过error_get_last解析错误信息。

我使用set_error_handler 和error_get_last 返回NULL,除非我:

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

  2. 或者让它返回FALSE。

我想这是由于 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 能正常工作。

【问题讨论】:

  • 您会接受使用不同的(用户定义的)函数吗?因为如果你愿意,你可以将最后一个错误存储在一个全局变量中,并拥有一个只执行return $GLOBALS['varname']; 的函数
  • 不接受返回false 吗?如果有,为什么?
  • 另外,您是否尝试过为$php_errormsg 赋值?我不知道这是否会实现(甚至影响)任何事情,但可能值得一试......
  • @Jon - 因为它执行两个错误处理程序:首先是我的,然后是 PHP 的。我的是替代品,而不是补充品。
  • @ÁlvaroG.Vicario:我明白这一点。我的问题也可以表述为“如果让 PHP 的错误处理程序执行,它会导致什么问题?”。

标签: php error-handling


【解决方案1】:

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

玩了一会儿,我发现:

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 以外的其他内容,但由于使用@ 抑制了错误,PHP 不会输出任何内容.似乎为了避免无限递归,从注册的错误处理函数中调用trigger_error() 不会调用错误处理程序——这对我们有利。

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

这是一个可怕的、可怕的、可怕的黑客攻击——但由于没有官方认可的方式来做到这一点,黑客本质上就是你所要求的。

【讨论】:

    【解决方案2】:

    您可以更改自定义错误处理程序以返回 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-18
      • 2018-04-29
      • 2011-06-01
      • 1970-01-01
      • 2010-12-26
      • 2013-01-04
      • 2011-04-21
      相关资源
      最近更新 更多