On Error Handling and Closures

The error suppression operator in PHP ("@") is often seen as a necessary
evil. Many, many low-level function will return a value indicating an error,
but also raise an E_NOTICE or E_WARNING -- things
you might be able to recover from, or conditions where you may want to raise
an exception.

Seems straight-forward enough, right? But it's wrong on so many levels.

The error doesn't magically go away. If you've got PHP's log setup,
you're going to be getting a log entry each time the suppressed
statement errors.

Error suppression is expensive. Like, really, really expensive. A
special error handler is registered to prevent the error propagating
to the display (if display_errors is enabled), but errors
are still sent to the log (as noted above). When done, the original
error handler has to be restored.

If you use things like error_get_last(), you may find that
if you have many error suppressions, it returns something unrelated to
the error that just occurred.

PHPUnit, anyone? Error suppression and PHPUnit do not play well
together. And there's a reason for that: often suppressed errors are
indicative of bigger issues.

So, how do you address it?

PHP has two functions to assist with this: set_error_handler()
and restore_error_handler(). The first takes a callable
argument, and optionally a mask of error levels to which it will respond;
the second is used to return error handling to the previously set handler.

Traditionally, these have been a pain to use, as you have to create
individual functions or methods for handlers, and methods must have public
visibility, even if the functionality is internal to the class.

With PHP 5.3, we get a new option, however: closures.

With closures, error handlers are still a pain to use, but you now get to
scope the handlers directly in the context of the application flow. Let's
look at an example:

The code isn't necessarily succinct, which is one reason many gravitate
towards using error suppression instead. However, it has the benefit of
being context-sensitive and robust, which is always a good goal.