我可以尝试/发出警告吗?

use*_*196 334 php error-handling try-catch

我需要从一些php本机函数中捕获一些警告,然后处理它们.

特别:

array dns_get_record  ( string $hostname  [, int $type= DNS_ANY  [, array &$authns  [, array &$addtl  ]]] )
Run Code Online (Sandbox Code Playgroud)

当DNS查询失败时,它会发出警告.

try/ catch不起作用,因为警告不是例外.

我现在有2个选择:

  1. set_error_handler 看起来有点矫枉过正,因为我必须使用它来过滤页面中的每个警告(这是真的吗?);

  2. 调整错误报告/显示,以便这些警告不会回显到屏幕,然后检查返回值; 如果是false,则没有找到主机名的记录.

这里的最佳做法是什么?

Phi*_*ber 356

设置和恢复错误处理程序

一种可能性是在调用之前设置自己的错误处理程序,稍后使用恢复先前的错误处理程序restore_error_handler().

set_error_handler(function() { /* ignore errors */ });
dns_get_record();
restore_error_handler();
Run Code Online (Sandbox Code Playgroud)

您可以构建这个想法并编写一个可重用的错误处理程序,为您记录错误.

set_error_handler([$logger, 'onSilencedError']);
dns_get_record();
restore_error_handler();
Run Code Online (Sandbox Code Playgroud)

将错误转化为异常

您可以使用set_error_handler()ErrorException类将所有php错误转换为异常.

set_error_handler(function($errno, $errstr, $errfile, $errline, $errcontext) {
    // error was suppressed with the @-operator
    if (0 === error_reporting()) {
        return false;
    }

    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    dns_get_record();
} catch (ErrorException $e) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

使用自己的错误处理程序时需要注意的重要一点是,它将绕过error_reporting设置并将所有错误(通知,警告等)传递给错误处理程序.您可以设置第二个参数set_error_handler()来定义要接收的错误类型,或使用... = error_reporting()错误处理程序内部访问当前设置.

抑制警告

另一种可能性是使用@运算符抑制调用并检查之后的返回值dns_get_record().但是我建议反对这个,因为触发了错误/警告,而不是被抑制.

  • 关于将警告变为异常的说明:警告不会中止您的应用程序 - *未被捕获*异常将会执行! (5认同)
  • 是否可以在函数调用之前设置我自己的错误处理程序,然后在完成错误检查时设置restore_error_handler? (3认同)
  • 谢谢; 这有帮助.(他们说PHP不是灾难.) (3认同)
  • 如果有许多并发请求,这将是线程安全的,并且每个请求都是1.set_error_handler().2.doit 3.restore_error_handler? (2认同)
  • +1以避免使用@来抑制错误。E_WARNING实际上是一个非致命错误。通常,您应该始终尝试适当地处理错误。如果您的应用程序需要使用set_error_handler,则需要这样做。通常建议记录错误并在生产环境中禁用它们的显示。检查日志后,您可以看到在开发环境中的何处进行更改。我见过@ fopen / @ unlink的实例太多了,想知道为什么开发人员没有执行检查来避免错误或使用set_error_handler处理错误。 (2认同)

小智 144

真正有效的解决方案是使用E_WARNING参数设置简单的错误处理程序,如下所示:

set_error_handler("warning_handler", E_WARNING);
dns_get_record(...)
restore_error_handler();

function warning_handler($errno, $errstr) { 
// do something
}
Run Code Online (Sandbox Code Playgroud)

  • 也可以在这里使用匿名`callable`而不是带有函数声明的字符串 (4认同)
  • 优秀!只需`trow new\Exception($ errstr,$ errno);```warning_handler`函数.谢谢. (3认同)
  • 这是这里最好的答案! (2认同)

Gur*_*Bob 28

小心@操作员 - 虽然它可以抑制警告,但它也可以抑制致命错误.我花了很多时间在有人编写的系统中调试问题,@mysql_query( '...' )问题是mysql支持没有加载到PHP中,它引发了一个无声的致命错误.对于那些属于PHP核心的东西来说是安全的,但小心使用它.

bob@mypc:~$ php -a
Interactive shell

php > echo @something(); // this will just silently die...
Run Code Online (Sandbox Code Playgroud)

没有进一步的输出 - 好运调试这个!

bob@mypc:~$ php -a
Interactive shell

php > echo something(); // lets try it again but don't suppress the error
PHP Fatal error:  Call to undefined function something() in php shell code on line 1
PHP Stack trace:
PHP   1. {main}() php shell code:0
bob@mypc:~$ 
Run Code Online (Sandbox Code Playgroud)

这次我们可以看出它失败的原因.


sda*_*aau 5

我想尝试/捕获警告,但同时保持通常的警告/错误记录(例如/var/log/apache2/error.log); 处理程序必须返回的false.但是,由于"throw new ..."语句基本上会中断执行,因此必须执行"wrap in function"技巧,同样在下面讨论:

有没有一种静态方法在php中抛出异常

或者,简而言之:

  function throwErrorException($errstr = null,$code = null, $errno = null, $errfile = null, $errline = null) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
  }
  function warning_handler($errno, $errstr, $errfile, $errline, array $errcontext) {
    return false && throwErrorException($errstr, 0, $errno, $errfile, $errline);
    # error_log("AAA"); # will never run after throw
    /* Do execute PHP internal error handler */
    # return false; # will never run after throw
  }
  ...
  set_error_handler('warning_handler', E_WARNING);
  ...
  try {
    mkdir($path, 0777, true);
  } catch (Exception $e) {
    echo $e->getMessage();
    // ...
  }
Run Code Online (Sandbox Code Playgroud)

编辑:仔细检查后,事实证明它不起作用:" return false && throwErrorException ..."基本上不会抛出异常,只需登录错误日志; 删除" false &&"部分,如" return throwErrorException ...",将使异常抛出工作,但不会登录error_log ...我仍然保持这个发布,但是,因为我没有看到这种行为记录在别处.


小智 5

将这些代码行与file_get_contents()对外部 url 的调用结合起来可以帮助我更好地处理诸如“无法打开流:连接超时”之类的警告:

set_error_handler(function ($err_severity, $err_msg, $err_file, $err_line, array $err_context)
{
    throw new ErrorException( $err_msg, 0, $err_severity, $err_file, $err_line );
}, E_WARNING);
try {
    $iResult = file_get_contents($sUrl);
} catch (Exception $e) {
    $this->sErrorMsg = $e->getMessage();
}
restore_error_handler();
Run Code Online (Sandbox Code Playgroud)

该解决方案也适用于对象上下文。您可以在函数中使用它:

public function myContentGetter($sUrl)
{
  ... code above ...
  return $iResult;
}
Run Code Online (Sandbox Code Playgroud)

  • 处理函数中的最后一个参数 (`$err_context`) 已在 PHP 8 (https://www.php.net/manual/en/function.set-error-handler.php) 中删除。 (2认同)