PHP 中的错误处理

2022-08-30 14:33:05

我熟悉一些基础知识,但我想了解更多的是何时以及为什么应该在PHP中使用错误处理(包括抛出异常),特别是在实时站点或Web应用程序上。它是否可能被过度使用,如果是这样,过度使用是什么样子的?是否存在不应使用它的情况?另外,在错误处理方面有哪些常见的安全问题?


答案 1

要补充已经说过的一件事是,将Web应用程序中的任何错误记录到日志中至关重要。这样,正如 Jeff “Coding Horror” Atwood 所建议的那样,你将知道你的用户何时遇到你的应用问题(而不是“问他们怎么了”)。

为此,我建议使用以下类型的基础结构:

  • 在数据库中创建一个“崩溃”表和一组用于报告错误的包装类。我建议为崩溃设置类别(“阻止”,“安全”,“PHP错误/警告”(与异常)等)。
  • 在所有错误处理代码中,确保记录错误。这样做始终如一地取决于您构建API的程度(上一步) - 如果做得好,记录崩溃应该是微不足道的。

额外的信用:有时,您的崩溃将是数据库级崩溃:即.DB服务器停机等。如果是这种情况,您的错误日志记录基础结构(上图)将失败(您无法将崩溃记录到数据库,因为日志会尝试写入数据库)。在这种情况下,我会将 Crash 包装器类中的故障转移逻辑写入

  • 向管理员发送电子邮件,和/或
  • 将崩溃的详细信息记录到纯文本文件中

所有这些听起来都像是矫枉过正,但相信我,这会影响你的应用程序是被接受为“稳定”还是“片状”。这种差异来自这样一个事实,即所有应用程序一直都是不稳定/崩溃的,但是那些了解其应用程序所有问题的开发人员有机会实际修复它。


答案 2

粗略地说,错误是PHP中的遗留问题,而例外是处理错误的现代方法。那么最简单的事情就是设置一个错误处理程序,它会引发异常。这样,所有错误都转换为异常,然后您可以简单地处理一个错误处理方案。下面的代码会将错误转换为异常:

function exceptions_error_handler($severity, $message, $filename, $lineno) {
  if (error_reporting() == 0) {
    return;
  }
  if (error_reporting() & $severity) {
    throw new ErrorException($message, 0, $severity, $filename, $lineno);
  }
}
set_error_handler('exceptions_error_handler');
error_reporting(E_ALL ^ E_STRICT);

但是,在某些情况下,代码是专门为处理错误而设计的。例如,DomDocumentschemaValidate 方法在验证文档时会引发警告。如果将错误转换为异常,它将在第一次失败后停止验证。有时这是您想要的,但是在验证文档时,您实际上可能希望所有失败。在这种情况下,您可以临时安装一个错误处理程序来收集错误。这里有一个小片段,我用于这个目的:

class errorhandler_LoggingCaller {
  protected $errors = array();
  function call($callback, $arguments = array()) {
    set_error_handler(array($this, "onError"));
    $orig_error_reporting = error_reporting(E_ALL);
    try {
      $result = call_user_func_array($callback, $arguments);
    } catch (Exception $ex) {
      restore_error_handler();
      error_reporting($orig_error_reporting);
      throw $ex;
    }
    restore_error_handler();
    error_reporting($orig_error_reporting);
    return $result;
  }
  function onError($severity, $message, $file = null, $line = null) {
    $this->errors[] = $message;
  }
  function getErrors() {
    return $this->errors;
  }
  function hasErrors() {
    return count($this->errors) > 0;
  }
}

还有一个用例:

$doc = new DomDocument();
$doc->load($xml_filename);
$validation = new errorhandler_LoggingCaller();
$validation->call(
  array($doc, 'schemaValidate'),
  array($xsd_filename));
if ($validation->hasErrors()) {
  var_dump($validation->getErrors());
}

推荐