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

7

odbc_errormsg并没有像它应该的那样报告odbc_execute中的错误消息,它只是抛出了一个警告。因此,我被迫编写了一个hack来通过error_get_last解析错误消息。

我正在使用set_error_handlererror_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正常工作。


返回 false 不可接受吗?如果是,为什么? - Jon
2
@ÁlvaroG.Vicario:我理解。我的问题也可以表述为“如果让PHP的错误处理程序执行,会引起什么问题?” - Jon
@DaveRandom - 我知道有很多方法可以替换 error_get_last()。我只想编写一个自定义错误处理程序,不会破坏其他功能。/// 设置 $php_errormsg 并不能防止 error_get_last() 返回 NULL(我刚测试过)。 - Álvaro González
@ÁlvaroG.Vicario:我问这个问题是因为我在考虑可能的黑客攻击。您是否尝试在自己的处理程序中重新实现 error_get_last 的功能(即保存到某个变量中并稍后获取它)?乍一看,这似乎是最清洁的解决方案。 - Jon
@Jon - 与JavaScript不同,PHP不允许重新定义函数。我可以编写自己的函数,但不能将其命名为error_get_last() - Álvaro González
显示剩余5条评论
2个回答

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的值,但由于使用了@禁止了错误输出。为了避免无限递归,从注册的错误处理程序函数内部调用trigger_error()不会触发错误处理程序,这在这种情况下起到了作用。
显然,错误代码已被修改,但如果需要,可以将其转换为相关的E_USR_*代码。但我怀疑您真正想要的是字符串值,这个方法将允许您获得它。不幸的是,您还失去了行号和文件信息,虽然您可能可以通过在错误处理程序内部执行涉及堆栈跟踪的操作或至少将其包含在传递的参数的字符串中来获取该信息。
这是一个可怕、可怕、可怕的黑客技巧——但因为没有官方认可的方法来实现这一点,所以您基本上就是在寻找一种黑客技巧。

0
你可以将自定义错误处理程序更改为在忽略错误时返回false(使用@运算符)。
function custom_error_handler($errno, $errstr, $errfile, $errline){
    $ignore = ($errno & error_reporting()) == 0;
    if ($ignore) {
        return FALSE;
    }
    echo "[Error happened: $errstr]\n";
    return TRUE;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接