• yii2.0框架的错误和异常处理机制


     

    FROM : http://tech.lubanr.com/2015/12/12/yii2-0框架的错误和异常处理机制/

    在应用开发中,错误和异常处理机制是一块比较重要的模块。yii框架有专门的模块来进行错误和异常处理,本文尝试从yii2.0的源码出发,对yii框架的错误和异常处理机制做一个说明。

    yii2.0中,错误和异常处理最先接触到的就是 frontend/config/main.php 中的 component中的一项配置 
    'errorHandler' => ['errorAction'=>'site/error']

    我们先记下这个配置,然后来看看yii框架的启动过程以及错误和异常处理在yii框架中的注册过程。

    yii框架的入口页面只有一个: frontend/web/index.php, 所有的访问都会经过nginx重写到这个脚本上(静态文件除外)。

    该文件的内容如下:

    defined('YII_DEBUG') or define('YII_DEBUG', true);

    defined('YII_ENV') or define('YII_ENV', 'dev');

    require(__DIR__ . '/../../vendor/autoload.php');

    require(__DIR__ . '/../../vendor/yiisoft/yii2/Yii.php');

    require(__DIR__ . '/../../common/config/bootstrap.php');

    require(__DIR__ . '/../config/bootstrap.php');

    $config = yiihelpersArrayHelper::merge(

    require(__DIR__ . '/../../common/config/main.php'),

    require(__DIR__ . '/../../common/config/main-local.php'),

    require(__DIR__ . '/../config/main.php'),

    require(__DIR__ . '/../config/main-local.php')

    );

    $application = new yiiwebApplication($config);

    $application->run();

    可以看出,$application是核心所在,我们来看看$application都干了些什么

    (yiiaseApplication 195行)

    yiiwebApplication在初始化的时候,会调用基类 yiiaseApplication的init函数,在init中,有这样一行代码:(第204行)

    $this->registerErrorHandler($config);

    改行的作用是在application中注册error和exception处理。 
    protected function registerErrorHandler(&$config) 

    if (YII_ENABLE_ERROR_HANDLER) { 
    if (!isset($config['components']['errorHandler']['class'])) { 
    echo "Error: no errorHandler component is configured. "; 
    exit(1); 

    $this->set('errorHandler', $config['components']['errorHandler']); 
    unset($config['components']['errorHandler']); 
    $this->getErrorHandler()->register(); 

    }

    registerErrorHandler方法的定义如上。$config中的components[‘errorHandler’][‘class’]在webApplication中的coreComponents变量定义并在preInit()函数中被merge到config中来,此处$config[‘components’][‘errorHandler’][‘class’] = yiiwebErrorHandler,

    因此registerErrorHandler($config) 最终的结果是执行了ErrorHandler类中的register()方法。

    yiiwebErrorHandler的register方法代码:(在yiiaseErrorHandler中定义) 
    public function register() 

    ini_set('display_errors', false); 
    set_exception_handler([$this, 'handleException']); 
    if (defined('HHVM_VERSION')) { 
    set_error_handler([$this, 'handleHhvmError']); 
    } else { 
    set_error_handler([$this, 'handleError']); 

    if ($this->memoryReserveSize > 0) { 
    $this->_memoryReserve = str_repeat('x', $this->memoryReserveSize); 

    register_shutdown_function([$this, 'handleFatalError']); 
    }

    该方法主要做了两个动作 set_exception_handler和set_error_handler.

    我们先值考虑异常处理:异常处理由ErrorHandler实例的HandleException方法处理。 
    public function handleException($exception) 

    if ($exception instanceof ExitException) { 
    return; 
    }

    $this->exception = $exception;

    // disable error capturing to avoid recursive errors while handling exceptions

    $this->unregister();

    // set preventive HTTP status code to 500 in case error handling somehow fails and headers are sent

    // HTTP exceptions will override this value in renderException()

    if (PHP_SAPI !== 'cli') {

    http_response_code(500);

    }

    try {

    $this->logException($exception);

    if ($this->discardExistingOutput) {

    $this->clearOutput();

    }

    $this->renderException($exception);

    if (!YII_ENV_TEST) {

    Yii::getLogger()->flush(true);

    if (defined('HHVM_VERSION')) {

    flush();

    }

    exit(1);

    }

    } catch (Exception $e) {

    // an other exception could be thrown while displaying the exception

    $msg = "An Error occurred while handling another error: ";

    $msg .= (string) $e;

    $msg .= " Previous exception: ";

    $msg .= (string) $exception;

    if (YII_DEBUG) {

    if (PHP_SAPI === 'cli') {

    echo $msg . " ";

    } else {

    echo '

    ' . htmlspecialchars($msg, ENT_QUOTES, Yii::$app->charset) . '

    ';

    }

    } else {

    echo 'An internal server error occurred.';

    }

    $msg .= " $_SERVER = " . VarDumper::export($_SERVER);

    error_log($msg);

    if (defined('HHVM_VERSION')) {

    flush();

    }

    exit(1);

    }

    $this->exception = null; 
    }

    该方法处理完之后,程序退出,可以看到 renderException决定了最终异常的展现形式。renderException是一个纯虚函数,yiiwebErrorHandler里面有默认实现: 
    protected function renderException($exception) 

    if (Yii::$app->has('response')) { 
    $response = Yii::$app->getResponse(); 
    // reset parameters of response to avoid interference with partially created response data 
    // in case the error occurred while sending the response. 
    $response->isSent = false; 
    $response->stream = null; 
    $response->data = null; 
    $response->content = null; 
    } else { 
    $response = new Response(); 

    $useErrorView = $response->format === Response::FORMAT_HTML && (!YII_DEBUG || $exception instanceof UserException);

    if ($useErrorView && $this->errorAction !== null) {

    $result = Yii::$app->runAction($this->errorAction);

    if ($result instanceof Response) {

    $response = $result;

    } else {

    $response->data = $result;

    }

    } elseif ($response->format === Response::FORMAT_HTML) {

    if (YII_ENV_TEST || isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest') {

    // AJAX request

    $response->data = '

    ' . $this->htmlEncode($this->convertExceptionToString($exception)) . '

    ';

    } else {

    // if there is an error during error rendering it's useful to

    // display PHP error in debug mode instead of a blank screen

    if (YII_DEBUG) {

    ini_set('display_errors', 1);

    }

    $file = $useErrorView ? $this->errorView : $this->exceptionView;

    $response->data = $this->renderFile($file, [

    'exception' => $exception,

    ]);

    }

    } elseif ($response->format === Response::FORMAT_RAW) {

    $response->data = $exception;

    } else {

    $response->data = $this->convertExceptionToArray($exception);

    }

    if ($exception instanceof HttpException) {

    $response->setStatusCode($exception->statusCode);

    } else {

    $response->setStatusCode(500);

    }

    $response->send(); 
    }

    已经不需要再解释什么了,这个就是大家经常看到的异常出错页面的渲染处理过程,如果我们需要定制自己的异常处理方式,需要做的就是继承yiiaseErrorHandler,写一个定制的renderException,最后在$config中定制自己的errorHandler, 如:

    ‘errorHandler’=>[‘action’=>’site/error’, ‘class’=>’commonwebErrorHandler’]

  • 相关阅读:
    结构~函数~输入输出
    常用缀名
    结构
    枚举
    int argc char*argv[]
    字符串的操作
    字符串函数#include<string.h>
    指针的应用
    2019.1.25~2019.1.30学习总结
    v-for
  • 原文地址:https://www.cnblogs.com/iceman-/p/8550734.html
Copyright © 2020-2023  润新知