PHP7: Exceptions And Errors Handling
In the previous versions of PHP, there was no way to handle fatal errors in your code. Setting the global error handler with set_error_handler()
function doesn’t help, the script execution will be halted. This happens because of the engine. Fatal and recoverable fatal errors have been raised (like warnings or deprecations). But exceptions are thrown. This is the main difference from the script execution point of view.
In PHP5 there we 16 different types of errors:
The first four errors are fatal, they halt the script execution and don’t invoke the error handler. The E_RECOVERABLE_ERROR
behaves like a fatal error, but it invokes the error handler. There are some issues with this model of fatal errors:
- they cannot be normally handled (error handler is not called)
- the
finally
block will not be invoked - destructors are not called
The solution with these issues comes with using exceptions. Now, in PHP7 when a fatal or recoverable fatal error (E_ERROR
and E_RECOVERABLE_ERROR
) occurs a special exception will be thrown, rather than halting a script:
There are five pre-defined sub-classes of Error
base class:
TypeError
- an argument doesn’t match the required type hintParseError
-eval
fails to parse the given codeAssertionError
- an assertion fails (assert(...)
)ArithmeticError
- error during a mathematical operationDivizionByZeroError
- a sub-class ofArithmeticError
when dividing by 0
Here is a full hierarchy of exceptions in PHP7:
Throwable Interface
All exceptions and errors in PHP7 implement Throwable
interface:
This interface specifies methods that look identical to those of Exception
. The only difference is that Throwable::getPrevious()
method can return any instance of Throwable
and not only Exception
. The constructors of Exception
and Error
accept an instance of Throwable
as the previous exception.
Because both Error
and Exception
objects share the common interface, we can catch them:
In some situations, we can catch any exceptions and errors. For example logging or framework error handling:
User defined classes cannot implement Throwable
interface, they should extend from either Error
or Exception
classes. This was made for consistency: only instances of Exception
or Error
may be thrown.
In our packages, we can define package-specific interfaces by extending Throwable
interface. A class can implement extended Throwable
interface only if it extend either Exception
or Error
:
Error
In PHP7 fatal errors and recoverable fatal errors throw instances of Error
class, which implements Throwable
interface and can be caught using a try/catch
block:
There are several specific subclasses of the base Error
class: TypeError
, ParseError
, ArtihmeticError
, and AssertionError
.
TypeError
This error is thrown in two different scenarios:
- a function argument or return value doesn’t match a declared type hint
- an invalid number of arguments is passed to a built-in PHP function (strict mode only)
ParseError
ParseError
is thrown when there is a syntax error in include/require
file or it occurs while parsing eval()
function content:
ArithmeticError
ArithmeticError
is thrown when there is an error while performing mathematical operations:
- shifting by a negative value
- call to
intdiv()
that would result in a value outside the possible bounds of an integer
DivisionByZeroError
DivisionByZeroError
is thrown when an attempt is made to divide a number by zero:
- from intdiv() when the denominator is zero
- when zero is used as the denominator with the modulo (%) operator.
Note that on division by zero 1/0 and module by zero 1%0 an E_WARNING
is triggered first (probably for backward compatibility with PHP5), then the DivisionByZeroError
exception is thrown next.
AssertionError
AssertionError
is thrown when an assertion made via assert()
fails:
Cathing Errors
You should avoid catching Error
objects unless logging them for the future solution. Because Error
always points to code problems, not some temporary runtime issues. It is better to fix such problems instead of handling them at runtime. In general, Error
objects should be caught for logging and for performing any necessary cleanup.
Multi-Catch Exception Handling
In PHP7.1 when several different types of exceptions are handled the same way, we can use multi-catch instead of duplication of catch
statements:
In PHP7.1 we can use a single catch
statement to avoid code duplication: