We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Micro app and error handling

I'm trying to develop a micro app and struggle with error handling. I've seen the set_error_handler and set_exception_hander and $app->error(), my main bootstrap is encapsuled in a try/catch also, and so on, but don't know which one to use.

First question is: I cannot see which benefit I have when using $app->error() instead of set_exception_handler. When using the latter one I can catch \Error also and not only \Exception. So, why should I use the error-handler of the application?

Second question: When any error occurs, I simply want to send a 500 error to user without any custom error page and want this error to be logged to error file. What approach is useful? Writing custom handlers for errors and exceptions or let PHP handle it via display_errors=0 and error_log=<filename>? When using the latter one, it seems to me, that I can remove all custom handlers and the try/catch block for bootstrap, can't I?

edited Aug '18

I have central ErrorHandler class to handle any kind of errors, even fatal errors.

Phalcon side:

 $app->error([new ErrorHandler(), 'err']);

will catch throwable errors, which are catched here normally.

Then define shutdown function to handle fatal and all other native PHP errors (non-exceptions), this is usually done at FPC index.php place:

register_shutdown_function(function () use ($config) {
    //include error handler class
    if (!class_exists(__NAMESPACE__ . '\\' . 'ErrorHandler')) require APP_PATH . $config->application->controllersDir . $config->application->errorHandlerClassless;

    //define error buffer
    $d = ', '; $errmsg = ''; $lasterr = error_get_last() ? error_get_last() : null;

    //validate
    if (!count($lasterr)) return;

    //prepare error buffer
    foreach ($lasterr as $k => $v) $errmsg .= $k . ': ' . $v . $d;

    //Process error via handler class
    ErrorHandler::stopMiddleware(500, rtrim($errmsg, $d), 0xff);
});

Just remove my ErrorHandler calls and use whatever you need/want.

Last but not least, since you want to hide any output from the user and send only HTTP haders, put in your FPC:

//If the debug mode is on, display all errors, if not, do not display any errors
$config->_options->debug ? error_reporting(~0) : error_reporting(0);

e.g. force error_reporting(0); for none errors display.



4.2k

$app->error() does work for micro apps only? I assume for normal applications I have to use a dispatcher or something else? To supress error messages in browser I'm using ini_set('display_errors', 0); instead of error_reporting(0) as the latter one disabled logging also. If error() and register_shutdown_function() is sufficient to catch most of all internal PHP errors and exceptions, it seems to be worth a try. I'll think about it some more time.

BTW: Great to see another person who is using one-line IF and FOREACH clauses ;-)

edited Aug '18

$app->error() does work for micro apps only? I assume for normal applications I have to use a dispatcher or something else?

Yes, only in Micro.

To supress error messages in browser I'm using ini_set('display_errors', 0); instead of error_reporting(0) as the latter one disabled logging also.

Hmmm, I wasn't aware of that. Which logging? Phalcon internal component? I have no problems to save errors in file or any other location.

If error() and register_shutdown_function() is sufficient to catch most of all internal PHP errors and exceptions, it seems to be worth a try. I'll think about it some more time.

Indeed.

BTW: Great to see another person who is using one-line IF and FOREACH clauses ;-)

:)



4.2k
Accepted
answer

Ok, just want to give some feedback. I've created a separate class for error handling containing two action, one for exceptions and one for errors and attached it to native PHP handlers

$handler = new AppErrorHandler();
set_exception_handler([ $handler, 'exception' ]);
set_error_handler([ $handler, 'error' ]);

Sure, register_shutdown_function() is triggered always, but it seems not to be a clean solution to me. But your post gave me some inspirations, so thanks!

BTW: Also, I made my decision based on the fact, that calling nonexistant() is caught by register_shutdown_function() with your solution, but not with $app->error(). So by replacing $app->error() with set_exception_handler() I can handle it as a real exception.