TQ
dev.com

Blog about software development

Subscribe

PHP 7 error handling class

27 Jul 2021 - by 'Maurits van der Schee'

Since writing bug-free code is not possible it is very important that you can quickly reproduce and fix bugs. Any programmer will tell you that this is only possible with a good bug report. Not all bugs are about missing/wrong functionality, sometimes the application runs into an error. Fortunately error reports (or crash reports as they are sometimes called) can be automated. In this post I will explain how errors are handled in PHP and how you can collect and log error data.

Note: If you are just looking for something ready to use as-is in production then look at Whoops (included in Laravel).

Two error handlers

Non-fatal errors can be handled by a user-defined handler using the "set_error_handler" function. Fatal errors, on the other hand, are exceptions (since PHP 7) and exceptions (of type "Throwable") can be handled by a user-defined handler using the "set_exception_handler" function. Since all uncaught exceptions are also fatal this covers about everything. The error handler receives parameters describing the error, but these can be converted to an ErrorException (that you should construct, but not throw). Now all errors are exceptions and you can create and call a third handler to log or display them.

Uncatchable fatal errors

Not all fatal errors are handled as exceptions (in PHP 7). For instance the error "Maximum execution time of 1 second exceeded" cannot be caught with the above handlers. You need to register a user-defined shutdown handler using the "register_shutdown_function" function and request the last error using the "error_get_last" function. Note that you need to return "true" in the user-defined error handler to flag that you handled the error (avoiding it to be reported by the "error_get_last" function in the shutdown handler).

Note: There is an annoying bug in the shutdown handler causing the CWD (current working directory) to change. I worked around this by storing the CWD during startup and using that to generate an absolute path in the shutdown handler.

Development vs. production

In development I want to see all errors, while in production I want to log all errors. When a fatal error/exception occurs in production I want to avoid that the end-user sees all kinds of technical error messages and just show a text saying: "Oops! Something went wrong." The error message shown in development or stored in the log should contain a stack trace, so that I can understand where the error exactly occurred. Also important is the requested URL, that is often missing in PHP's error log. Once you understand the code you can easily add other parameters, such as a customer identifier in a multi-tenant system.

Load your errors into the database

Now that you have the errors logged in new-line delimited JSON format (NDJSON) you may do several things with them. One is to load them into the database of your application so that you can view them in a control panel for administrators. You may also write an error report viewer or create a mailer script that warns you of important errors. I'm sure that once you have the data you can think of things that will speed up fixing the cause of these error reports.

Getting started

Here is the file "ErrorReporting.php":

https://gist.github.com/mevdschee/98dc3f6d246acf4a534be905afa53003

You can use it by adding the following to (the front-controller of) your PHP application:

<?php
include 'ErrorReporting.php';
ErrorReporting::start(true); // false for production
include 'error.php'; // some file with a PHP error

Happy programming!

Links


PS: Liked this article? Please share it on Facebook, Twitter or LinkedIn.