ThinkPHP的异常处理
TP框架的基础类加载多放在\Think\Think这个类里,异常处理也不例外.
如图,TP在start方法中定义自定义错误和异常处理函数,以及脚本关闭函数.下面来看看各自的源码,在此之前先看一个错误输出函数,这个函数将会在各个处理函数中被调用:
static public function halt($error) {.
$e = array();
if (APP_DEBUG || IS_CLI) {
//调试模式下输出错误信息
if (!is_array($error)) {
// 获取当前脚本的回调跟踪
$trace = debug_backtrace();
$e['message'] = $error;
$e['file'] = $trace[0]['file'];
$e['line'] = $trace[0]['line'];
ob_start();
debug_print_backtrace();
$e['trace'] = ob_get_clean();
} else {
$e = $error;
}
if(IS_CLI){
exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']);
}
} else {
//否则定向到错误页面
$error_page = C('ERROR_PAGE');
if (!empty($error_page)) {
redirect($error_page);
} else {
$message = is_array($error) ? $error['message'] : $error;
$e['message'] = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');
}
}
// 包含异常页面模板
$exceptionFile = C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');
include $exceptionFile;
exit;
}
- 调试模式下获取错误$error中的信息,记录下错误的信息,行数,文件,以及回调跟踪.然后在错误模板中打印输出.
- 命令行模式下,关闭脚本,并将错误信息以gbk格式输出.
- 生产模式下,直接进入错误模板.
捕获致命错误:
static public function fatalError() {
// 将错误记录保存进日志:错误路径,错误时间和错误类型等
Log::save();
if ($e = error_get_last()) { // 捕获最后一个错误
switch($e['type']){
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
ob_end_clean(); // 关闭并清空缓存区
self::halt($e); // 错误输出
break;
}
}
}
TP将发生错误这一时间记录进日志文件,之后清空并关闭缓存区,使用自定义函数halt将错误输出.
自定义异常处理函数:
static public function appException($e) {
$error = array();
$error['message'] = $e->getMessage();
$trace = $e->getTrace();
if('E'==$trace[0]['function']) {
$error['file'] = $trace[0]['file'];
$error['line'] = $trace[0]['line'];
}else{
$error['file'] = $e->getFile();
$error['line'] = $e->getLine();
}
$error['trace'] = $e->getTraceAsString();
Log::record($error['message'],Log::ERR);
// 发送404信息
header('HTTP/1.1 404 Not Found');
header('Status:404 Not Found');
self::halt($error);
}
自定义错误处理函数:
static public function appError($errno, $errstr, $errfile, $errline) {
switch ($errno) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
ob_end_clean();
$errorStr = "$errstr ".$errfile." 第 $errline 行.";
if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);
self::halt($errorStr);
break;
default:
$errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
self::trace($errorStr,'','NOTIC');
break;
}
}