In Yii2, by default, all Exception are processed, a special handler is responsible for this. If a bad situation occurs during the processing of a request (for example, incorrect data came from the client), then an exception may be thrown. The handler will form a humanoid response.
Interestingly, in this case, the error “Warning: Uncaught exception” is not displayed in the error log. It may seem that all exceptions are caught by the framework. But it is not. Some time ago, a monitoring tool (in our case, New Relic), which displays information about all exceptions displayed in errors (exactly as “Warning: Uncaught exception”), was considered to be on our project, considers these exceptions to be unprocessed. We had to do something about it.
Below I will talk about the exception handling scheme that I have chosen in the end. It is possible that someone else will come in handy.
')
Why processed exceptions are considered not caught
In Yii2, the error handler is specified by the
set_exception_handler () function. This function defines a handler for not caught exceptions. At the same time, exceptions, though processed, are still not caught. In order for exceptions to be considered caught, they still need to be explicitly caught, wrapping calls in try-catch. In every 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 out the exception
yii \ base \ ExitException (or its descendant), then such an exception is handled by the framework. For clarity, here’s how it 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.
- If nothing is broken, there is just a minor misunderstanding - a curve came a web request to the client, or there was no not very critical requested data.
- If something broke.
In the first case, you do not need to log the event as an error and do not need to deal with it.
In the second case, you need to log the problem in order to know about what happened and deal with the problem.
For the first case, I created such a class, inherited from yii \ base \ ExitException. So that the result of the script was not an empty page, the answer is generated directly in the exception.
<?php namespace app\components; use yii; use yii\base\ExitException; class GoodException extends ExitException { public function __construct($name, $message = null, $code = 0, $status = 500, \Exception $previous = null) {
And also created another presentation.
<?php use yii\helpers\Html; $this->title = $name; ?> <?php $this->beginContent('@app/views/layouts/main.php'); ?> <div class="site-error"> <h1><?= Html::encode($this->title) ?></h1> <div class="alert alert-danger"> <?= nl2br(Html::encode($message)) ?> </div> <p> The above error occurred while the Web server was processing your request. </p> <p> Please contact us if you think this is a server error. Thank you. </p> </div> <?php $this->endContent(); ?>
Total
So, to throw out the “cultural” exception, we write:
Such exceptions will be intercepted and a neat answer will be returned to the client. Such events will not appear in the error log.
All other exceptions, if you clearly do not 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(' ');