📜 ⬆️ ⬇️

Error handling scheme in Yii

Hello!
The error handling process in Yii was not completely transparent to me from the very first days of using this framework. Even despite the presence in the documentation of a special section Error Handling . In what cases what view is used, how does ajax or debug mode affect, why do I need errorAction, what are the differences when handling exceptions?
In the end, after digging into the documentation and the source code of the framework, I drew a visual error-handling scheme, which personally turned out to be very useful for me and probably will be useful to someone else.
Under the cut scheme itself and some comments to it.


0. Error levels

So, standardly, Yii handles only errors of the warning and notice level, as well as uncaught exceptions . To handle fatal errors you need to use register_shutdown_function (about this at the end of the article).

1. Let's go!

In the event of a warning or uncaught exception, Yii will process them if two constants are set respectively:
YII_ENABLE_ERROR_HANDLER = true YII_ENABLE_EXCEPTION_HANDLER = true 

Both errors and exceptions are handled in Yii in a similar scenario. But there are certain differences that I will mention.
image
')
2. Logging

First of all, the error or exception information is written to the log - the function Yii :: log () .

3. Call event

Next, the onError ( onException ) event is called . If there is a custom handler for these events, then it is called, performs the necessary actions, and can stop further event processing (by setting event-> handled = true ). You can hang the handler like this:
 $app->onError=function($event) { ... } 

or via the attachEventHandler () method.

4. Connection ErrorHandler

If event processing continues ( event-> handled = false ), the standard component of the yii application ErrorHandler comes into play (by default it is always not null). It calls the corresponding handleError () or handleException () method. Inside these similar methods there is an important distinction between error and exception (available in the current version of Yii 1.1.9):

Depending on this, either the simplest html error output via app-> displayError (), or the cunning function render () of the ErrorHandler component is called.
Previously, ajax check was also in handleException (), but in 1.1.9 it was removed, which makes it more convenient to handle exceptions on ajax requests — for example, to return json.

5. Cunning rendering in ErrorHandler

I call the ErrorHandler-> render () function “tricky” because it works a little differently than the controller's usual rendering:

The view search occurs sequentially in:
1. themes / ThemeName / views / system
2. protected / views / system
3. framework / views

6. Custom error display

In the case of an established errorAction (for example, “site / error” in the config), this method, I repeat, is used to custom display errors and exceptions in production mode. It is convenient to make a different conclusion for ajax and non-ajax requests. Also note that here the output can be carried out in the overall layout of the application through views / site / error.php (as opposed to views / system / errorXXX.php , which contain the full html code of the page).

Afterword: Handling Fatal Errors

And what about the fatal errors? Their interception through the register_shutdown_function is currently not implemented in Yii. The solution I use now in projects is:
1. When the application is initialized, register the shutdown handler.
2. In the handler, check for the error and its level in error_get_last () . If the error has already been processed, NULL will return.
3. Run the entire processing mechanism via app-> handleError () , i.e. close to the beginning of the scheme

When using error_get_last (), it is important to note that this function ignores the error_reporting directive and the @ character before the operator, i.e. may contain E_NOTICE that are not visible and not processed (for example, calling @session_start () when sessions are running).
Therefore, in the handler, I check only fatal errors.
I also set errorAction = null - then, as can be clearly seen from the diagram, the system error.php view will be shown, which is safer than running another controller action, where the probability of a repeated error is higher:
 class WebApplication extends CWebApplication { protected function init() { register_shutdown_function(array($this, 'onShutdownHandler')); parent::init(); } public function onShutdownHandler() { // 1. error_get_last() returns NULL if error handled via set_error_handler // 2. error_get_last() returns error even if error_reporting level less then error $e = error_get_last(); $errorsToHandle = E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING; if(!is_null($e) && ($e['type'] & $errorsToHandle)) { $msg = 'Fatal error: '.$e['message']; // it's better to set errorAction = null to use system view "error.php" instead of run another controller/action (less possibility of additional errors) yii::app()->errorHandler->errorAction = null; // handling error yii::app()->handleError($e['type'], $msg, $e['file'], $e['line']); } } } 


Conclusion

In my opinion, error handling in Yii is not very simple, but it has a lot of flexibility. I am pleased to listen to your comments and suggestions.
Thank you for attention!

UPD:
Laid out the scheme in PDF format

Source: https://habr.com/ru/post/136138/


All Articles