内容简介:错误及异常处理机制文件是/thinkphp/library/think/Error.php,在框架引导文件的的基础文件base.php中注册(不知道的可以去看《《源码分析(二)—入口篇》》),通过thinkError::register()进行的注册。该方法做了四件事情:php的报错级别有:E_STRICT,E_ALL, E_USER_WARNING等,具体可查看[php
源码分析
错误及异常处理机制
错误及异常处理机制文件是/thinkphp/library/think/Error.php,在框架引导文件的的基础文件base.php中注册(不知道的可以去看《《源码分析(二)—入口篇》》),通过thinkError::register()进行的注册。
/**
* 注册异常处理
* @access public
* @return void
*/
public static function register()
{
error_reporting(E_ALL);
set_error_handler([__CLASS__, 'appError']);
set_exception_handler([__CLASS__, 'appException']);
register_shutdown_function([__CLASS__, 'appShutdown']);
}
该方法做了四件事情:
- 设置报错级别 E_ALL为E_STRICT所有报错。
- 设置错误处理函数,set_error_handler([__CLASS__, 'appError'])
- 设置异常处理函数,set_exception_handler([__CLASS__, 'appException']);
- 设置程序异常终止处理函数,register_shutdown_function([__CLASS__, 'appShutdown']);
PHP报错级别
php的报错级别有:E_STRICT,E_ALL, E_USER_WARNING等,具体可查看[php
预定义常量]( http://php.net/manual/zh/erro... 。
错误处理函数
thinkphp中注册了thinkError::appError()方法对错误进行处理。
/**
* 错误处理
* @access public
* @param integer $errno 错误编号
* @param integer $errstr 详细错误信息
* @param string $errfile 出错的文件
* @param integer $errline 出错行号
* @return void
* @throws ErrorException
*/
public static function appError($errno, $errstr, $errfile = '', $errline = 0)
{
$exception = new ErrorException($errno, $errstr, $errfile, $errline);
// 符合异常处理的则将错误信息托管至 think\exception\ErrorException
if (error_reporting() & $errno) {
throw $exception;
}
self::getExceptionHandler()->report($exception);
}
在appError方法中,把符合异常处理的则将错误信息托管至系统的ErrorException,其他的异常通过thinkexceptionHandle进行处理。
//think\exception\ErrorException文件 /** * ThinkPHP错误异常 * 主要用于封装 set_error_handler 和 register_shutdown_function 得到的错误 * 除开从 think\Exception 继承的功能 * 其他和 PHP 系统\ErrorException功能基本一样 */ class ErrorException extends Exception { /** * 用于保存错误级别 * @var integer */ protected $severity; /** * 错误异常构造函数 * @param integer $severity 错误级别 * @param string $message 错误详细信息 * @param string $file 出错文件路径 * @param integer $line 出错行号 * @param array $context 错误上下文,会包含错误触发处作用域内所有变量的数组 */ public function __construct($severity, $message, $file, $line, array $context = []) { $this->severity = $severity; $this->message = $message; $this->file = $file; $this->line = $line; $this->code = 0; empty($context) || $this->setData('Error Context', $context); } /** * 获取错误级别 * @return integer 错误级别 */ final public function getSeverity() { return $this->severity; } }
errorException设置错误级别,错误信息,出错文件路径,行号,上下文。
对exception进行处理的是thinkexceptionHandle的report()方法:self::getExceptionHandler()->report($exception);
//self::getExceptionHandler()
/**
* 获取异常处理的实例
* @access public
* @return Handle
*/
public static function getExceptionHandler()
{
static $handle;
if (!$handle) {
// 异常处理 handle
$class = Config::get('exception_handle');
if ($class && is_string($class) && class_exists($class) &&
is_subclass_of($class, "\\think\\exception\\Handle")
) {
$handle = new $class;
} else {
$handle = new Handle;
if ($class instanceof \Closure) {
$handle->setRender($class);
}
}
}
return $handle;
}
这里有一个关键的地方是:static $handle; 声明该变量是静态变量时候,当赋值给该变量后,函数调用结束后不会销毁,直到脚本结束才会销毁。
这个逻辑就是判断$handle是否已经赋值,没有赋值,获取默认配置文件是否设置处理handle,如果设置,这个handle必须是\think\exception\Handle的子类(is_subclass_of($class, "\think\exception\Handle")),如果没有设置,那么用默认的thinkexceptionHandle调用report方法进行处理, 记录到日志文件中。
/**
* Report or log an exception.
*
* @param \Exception $exception
* @return void
*/
public function report(Exception $exception)
{
if (!$this->isIgnoreReport($exception)) {
// 收集异常数据
if (App::$debug) {
$data = [
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $this->getMessage($exception),
'code' => $this->getCode($exception),
];
$log = "[{$data['code']}]{$data['message']}[{$data['file']}:{$data['line']}]";
} else {
$data = [
'code' => $this->getCode($exception),
'message' => $this->getMessage($exception),
];
$log = "[{$data['code']}]{$data['message']}";
}
if (Config::get('record_trace')) {
$log .= "\r\n" . $exception->getTraceAsString();
}
Log::record($log, 'error');
}
}
把errorException的数据组装成对应的字符串,写入日志。
异常处理函数
thinkphp中注册了thinkError::appException()方法对错误进行处理。
/**
* 异常处理
* @access public
* @param \Exception|\Throwable $e 异常
* @return void
*/
public static function appException($e)
{
if (!$e instanceof \Exception) {
$e = new ThrowableError($e);
}
$handler = self::getExceptionHandler();
$handler->report($e);
if (IS_CLI) {
$handler->renderForConsole(new ConsoleOutput, $e);
} else {
$handler->render($e)->send();
}
}
方法和appError处理差不多,基本都是通过获取ExceptionHandle再调用handle的report方法,但是多了一步把异常呈现,如果是命令行写到命令行输出,如果是web的就把错误信息通过reponse响应返回客户端。
异常中止时执行的函数
thinkphp中注册了thinkError::appShutdown()方法对错误进行处理。
/**
* 异常中止处理
* @access public
* @return void
*/
public static function appShutdown()
{
// 将错误信息托管至 think\ErrorException
if (!is_null($error = error_get_last()) && self::isFatal($error['type'])) {
self::appException(new ErrorException(
$error['type'], $error['message'], $error['file'], $error['line']
));
}
// 写入日志
Log::save();
}
通过error_get_last()获取最后抛出的错误,把信息托管至thinkErrorException,在通过异常处理函数进行记录信息。最后写入日志。
总结
整体整个错误处理机制都是通过获取ExceptionHandle再调用handle的report方法,但是多了一步把异常呈现,如果是命令行写到命令行输出,如果是web的就把错误信息通过reponse响应返回客户端。默认的处理handle是thinkexceptionHandle,当然也可以自定义handle,但是必须是thinkexceptionHandle的子类, 通过self::getExceptionHandler的is_subclass_of($class, "\think\exception\Handle")可以知。
以上所述就是小编给大家介绍的《源码分析(四)—错误及异常处理篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Laravel 全局异常错误处理源码解析及使用场景
- MySQL DBA如何"土土"地利用源码解决没有遇到过的错误?
- golang在mac下源码安装时fatal error: MSpanList_Insert错误
- Golang学习笔记之错误处理error、panic (抛出错误),recover(捕获错误)
- c – 构建PBRT v2错误 – 错误1错误U1077:’if’:返回代码’0x1′
- !错误!在 Android 下这么用 ShowModal 是错误的!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Design and Analysis of Distributed Algorithms (Wiley Series on P
Nicola Santoro / Wiley-Interscience / 2006-10-27 / USD 140.95
This text is based on a simple and fully reactive computational model that allows for intuitive comprehension and logical designs. The principles and techniques presented can be applied to any distrib......一起来看看 《Design and Analysis of Distributed Algorithms (Wiley Series on P》 这本书的介绍吧!