Catching and handling exceptions in Yii2

    In Yii2, by default, all Exception are processed, a special handler is responsible for this. If a bad situation occurs during the processing of the request (for example, incorrect data came from the client), then an exception can be thrown. The handler will form a humanoid response.

    Interestingly, in this case, the “Warning: Uncaught exception” error is not displayed in the error log. It may seem that all exceptions are caught by the framework. But this is not so. Some time ago we installed a monitoring tool on our project (in our case, New Relic), which displays information about all thrown exceptions in errors (just like “Warning: Uncaught exception”), considers these exceptions to be unhandled. There was something to do with this.

    Below I will talk about the exception handling scheme that I ultimately chose. It is possible that someone else will come in handy.


    Why handled exceptions are considered not caught


    In Yii2, an error handler is set by the set_exception_handler () function . This function defines a handler for uncaught exceptions. At the same time, although the exceptions are handled, they are still not caught. For exceptions to be caught, they must still be caught explicitly, wrapping calls in try-catch. In each action of each controller, I really did not want to do this. I find it convenient to have a single point of interception.

    In Yii2, as it turned out, there is a ready-made option for this - if you throw a yii \ base \ ExitException exception (or a descendant from it), then this exception is handled by the framework. For clarity, here is how this is done in Application :: run ():

     public function run()
        {
            try {
                $this->state = self::STATE_BEFORE_REQUEST;
                $this->trigger(self::EVENT_BEFORE_REQUEST);
                $this->state = self::STATE_HANDLING_REQUEST;
                $response = $this->handleRequest($this->getRequest());
                $this->state = self::STATE_AFTER_REQUEST;
                $this->trigger(self::EVENT_AFTER_REQUEST);
                $this->state = self::STATE_SENDING_RESPONSE;
                $response->send();
                $this->state = self::STATE_END;
                return $response->exitStatus;
            } catch (ExitException $e) {
                $this->end($e->statusCode, isset($response) ? $response : null);
                return $e->statusCode;
            }
        }
    


    “Good” and “Bad” Exceptions


    It is convenient for me to throw exceptions in order to complete the processing of the request in two cases.
    1. If nothing has broken, there is simply a minor misunderstanding - a web-based request for a client came in a curve or there weren’t any not-so-critical requested data.
    2. If something is broken.

    In the first case, it is not necessary to log the event as an error and there is no need to deal with it.
    In the second case, you need to log the problem in order to know what happened and deal with the problem.

    For the first case, I created a class inherited from yii \ base \ ExitException. So that the result of the script was not a blank page, a response is generated directly in the exception.

    getView();
            $response = yii::$app->getResponse();
            $response->data = $view->renderFile('@app/views/exception.php', [
                'name' => $name,
                'message' => $message,
            ]);
            # Возвратим нужный статус (по-умолчанию отдадим 500-й)
            $response->setStatusCode($status);
            parent::__construct($status, $message, $code, $previous);
        }
    }
    

    And also created another view.
    title = $name;
    ?>
    beginContent('@app/views/layouts/main.php'); ?>
    

    title) ?>

    The above error occurred while the Web server was processing your request.

    Please contact us if you think this is a server error. Thank you.

    endContent(); ?>


    Total


    Thus, to throw a “cultural” exception, we write:
    # Выбрасываем исключение, которое будет поймано
    throw new GoodException('Проблемка', 'Эта проблема аккуратно обрабатывается');
    

    Such exceptions will be caught and an accurate response will be returned to the client. Such events will not get into the error log.

    All other exceptions, unless you explicitly catch them, will not be caught. And they will fall into errors. Those. for the second case, you can write
    throw new yii\base\ErrorException('Эта проблема критичная');
    

    Also popular now: