1、ThinkPHP源码学习-致命错误捕获及自定义错误输出

首先在 Think\Think::start() 静态方法中,使用 register_shutdown_function 函数注册致命错误处理方法。

register_shutdown_function('Think\Think::fatalError');

Think\Think::fatalError 方法中,首先记录错误日志,这个暂且不说。接着使用 error_get_last 函数获取错误信息,不过TP只匹配E_ERROR、E_PARSE、E_CORE_ERROR、E_COMPILE_ERROR、E_USER_ERROR 这五种错误类型,然后使用 ob_end_clean 函数清空并关闭输出缓冲区(这样做的目的是,不显示PHP自身的错误信息提示,而是采用自定义的错误提示),最后调用自定义错误提示方法。

// 致命错误捕获
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;
        }
    }
}

self::halt($e) 方法细节:

// 错误输出
static public function halt($error)
{
    $e = array();
    if (APP_DEBUG || IS_CLI) {
        //调试模式下输出错误信息
        if (!is_array($error)) {
            // 如果错误信息格式不是数组,使用回溯跟踪函数debug_backtrace,可以定位到错误文件及错误行号。
            $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)) {
            // 获取错误文件的URL路径,重定向至错误的文件,一般不会执行这段代码。
            redirect($error_page);
        } else {
            // 在线上部署时,出于安全考虑,不应显示过多的敏感信息,
            // 比如:错误文件及路径,错误行号,错误原因。
            // C('SHOW_ERROR_MSG')为false时,显示tp预定义好的错误提示:C('ERROR_MESSAGE') 页面错误!请稍后再试~。
            $message        = is_array($error) ? $error['message'] : $error;
            $e['message']   = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');
        }
    }

    // 最后一步就是加载错误模板,想用户展示错误信息
    // 路径:项目根\ThinkPHP\Tpl\think_exception.tpl
    // 至于模板是什么样子,自己可以随意写。
    
    // 包含异常页面模板
    $exceptionFile =  C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');
    include $exceptionFile;
    exit;
}


版权声明:本文为dreamsqifan原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。