PHP中的错误处理

时间:2020-03-06 14:43:51  来源:igfitidea点击:

我熟悉一些基本知识,但是我想了解的更多信息是何时以及为什么在PHP中使用错误处理(包括引发异常),尤其是在现场站点或者Web应用程序中。它是可以被过度使用的东西吗?如果可以的话,过度使用是什么样子?在某些情况下不应该使用它吗?此外,关于错误处理的一些常见安全问题是什么?

解决方案

未经处理的错误会停止脚本,仅凭这是处理它们的一个很好的理由。

通常,我们可以使用Try-Catch块来处理错误

try
{
    // Code that may error
}
catch (Exception $e)
{
    // Do other stuff if there's an error
}

如果要停止页面上显示的错误或者警告消息,则可以在呼叫之前添加@符号作为前缀。

@mysql_query($query);

但是,对于查询,通常最好执行这样的操作,以便我们对发生的事情有更好的了解。

@mysql_query($query)
    or die('Invalid query: ' . mysql_error() . '<br />Line: ' . __LINE__ . '<br />File: ' . __FILE__ . '<br /><br />');

我们可以将其存储在日志中,而不是输出mysql_error。这样,我们就可以跟踪错误(并且不依赖用户报告错误),并且可以排除故障。

最好的错误处理是对用户透明的类型,让代码找出问题,而无需让该用户同伴。

如果我们无法明确控制脚本正在处理的数据,则应使用错误处理。我倾向于在例如表单验证之类的地方频繁使用它。知道如何发现代码中容易出错的地方需要一些实践:一些常见的问题是在返回值的函数调用之后,或者在处理数据库查询的结果时。我们永远不要以为函数的返回值将是期望,并且我们应该确保在预期的情况下进行编码。尽管它们很有用,但我们不必使用try / catch块。很多时候,我们可以通过简单的if / else检查来解决问题。

错误处理与安全的编码实践紧密结合,因为有许多"错误"不会导致脚本简单崩溃。尽管不仅仅严格地讨论错误处理本身,但是addbytes在关于安全PHP编程的一些基础知识上有一篇不错的文章(共4篇),我们可以在这里找到。在stackoverflow上还有很多其他问题,例如mysql_real_escape_string和正则表达式,它们在确认用户输入数据的内容方面非常有力。

除了立即处理代码中的错误外,我们还可以利用

http://us.php.net/manual/zh/function.set-exception-handler.php

http://us.php.net/manual/zh/function.set-error-handler.php

我发现设置自己的异常处理程序特别有用。发生异常时,我们可以根据异常的类型执行不同的操作。

例如:当mysql_connet调用返回FALSE时,我抛出新的DBConnectionException(mysql_error())并以"特殊"方式处理它:记录错误,数据库连接信息(主机,用户名,密码)等,并甚至可以通过电子邮件发送给开发团队,通知他们数据库可能确实存在问题

我用它来补充标准错误处理。我不建议过度使用这种方法

要增加已经说过的一件事是,将Web应用程序中的任何错误记录到日志中是至关重要的。这样,就像Jeff" Coding Horror" Atwood所建议的那样,我们将知道用户何时遇到应用程序问题(而不是"向他们提出问题")。

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

  • 在数据库中创建一个"崩溃"表,并创建一组用于报告错误的包装器类。我建议为崩溃设置类别("阻止","安全"," PHP错误/警告"(与例外)等)。
  • 在所有错误处理代码中,请确保记录错误。持续执行此操作取决于我们构建API的能力(上述步骤)-如果操作正确,记录崩溃应该很简单。

额外的功劳:有时,崩溃将是数据库级的崩溃:例如,数据库服务器关闭等。如果是这种情况,错误日志记录基础结构(上述)将失败(我们无法将崩溃记录到数据库,因为日志会尝试写入数据库)。在那种情况下,我会在崩溃包装器类中将故障转移逻辑写入

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

所有这些听起来都有些过分,但是请相信我,这对应用程序被接受为"稳定"还是"不稳定"有所不同。造成这种差异的原因是,所有应用程序始终都以片状/崩溃开头,但那些知道其应用程序所有问题的开发人员就有机会进行实际修复。

恕我直言的最佳实践是使用以下方法:
1.创建一个错误/异常处理程序
2.在应用启动时启动
3.从那里处理所有错误

<?php

类Debug {

public static setAsErrorHandler() {
         set_error_handler(array(__CLASS__, '__error_handler'));
    }

public static function __error_handler($errcode, $errmsg, $errfile, $errline) {
       if (IN DEV) {
                print on screen
           }
           else if (IN PRO) {
                log and mail
           } 
    }

}

Debug :: setAsErrorHandler();

?>

粗略地说,错误是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);

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

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());
}

@的错误抑制非常慢。

我们还可以使用Google表单来捕获和分析异常,而无需维护数据库或者可公开访问的服务器。这里有一个教程来解释该过程。