PHP 中的错误处理
我熟悉一些基础知识,但我想了解更多的是何时以及为什么应该在PHP中使用错误处理(包括抛出异常),特别是在实时站点或Web应用程序上。它是否可能被过度使用,如果是这样,过度使用是什么样子的?是否存在不应使用它的情况?另外,在错误处理方面有哪些常见的安全问题?
我熟悉一些基础知识,但我想了解更多的是何时以及为什么应该在PHP中使用错误处理(包括抛出异常),特别是在实时站点或Web应用程序上。它是否可能被过度使用,如果是这样,过度使用是什么样子的?是否存在不应使用它的情况?另外,在错误处理方面有哪些常见的安全问题?
要补充已经说过的一件事是,将Web应用程序中的任何错误记录到日志中至关重要。这样,正如 Jeff “Coding Horror” Atwood 所建议的那样,你将知道你的用户何时遇到你的应用问题(而不是“问他们怎么了”)。
为此,我建议使用以下类型的基础结构:
额外的信用:有时,您的崩溃将是数据库级崩溃:即.DB服务器停机等。如果是这种情况,您的错误日志记录基础结构(上图)将失败(您无法将崩溃记录到数据库,因为日志会尝试写入数据库)。在这种情况下,我会将 Crash 包装器类中的故障转移逻辑写入
所有这些听起来都像是矫枉过正,但相信我,这会影响你的应用程序是被接受为“稳定”还是“片状”。这种差异来自这样一个事实,即所有应用程序一直都是不稳定/崩溃的,但是那些了解其应用程序所有问题的开发人员有机会实际修复它。
粗略地说,错误是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());
}