我熟悉一些基础知识,但我想知道更多关于何时以及为什么错误处理(包括抛出异常)应该在PHP中使用,尤其是在实时网站或Web应用程序上.是否可以过度使用,如果是这样,过度使用会是什么样的?是否有不应该使用的情况?此外,有关错误处理的一些常见安全问题是什么?
添加到已经说过的内容的一件事是,将Web应用程序中的任何错误记录到日志中是至关重要的.这样,正如Jeff"Coding Horror"Atwood建议的那样,你会知道你的用户何时遇到应用程序问题(而不是"问他们有什么不对劲").
为此,我建议使用以下类型的基础结构:
在数据库中创建一个"崩溃"表和一组用于报告错误的包装类.我建议为崩溃设置类别("阻止","安全","PHP错误/警告"(与例外)等).
在所有错误处理代码中,请确保记录错误.这样做一直取决于你构建API的程度(上面的步骤) - 如果做得对,记录崩溃应该是微不足道的.
额外的功劳:有时,您的崩溃将是数据库级崩溃:即数据库服务器崩溃等.如果是这种情况,您的错误记录基础结构(上面)将失败(您无法将崩溃记录到数据库,因为日志尝试写入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);
但有几种情况,其中代码专门设计用于处理错误.例如,在验证文档时引发警告的schemaValidate
方法DomDocument
.如果将错误转换为异常,它将在第一次失败后停止验证.有时这是你想要的,但是在验证文档时,你可能真的想要所有的失败.在这种情况下,您可以临时安装收集错误的错误处理程序.这是一个小片段,我用于此目的:
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()); }