PHP 7 Exception Handling

Exception handling is one of the essential parts of your code. The handling saves your code in the most unusual circumstances.
Making your exception handling more easier, PHP 7 has introduced two new classes that assist a developer in handling errors with ease. However, before the introduction of these classes in PHP 7, exception error classes were written to handle the different type of errors. These exception error classes are discussed in detail below.
php7handling

Throwable Class:

It is one of the new classes introduced in PHP 7. It is the class from which, Exception and Error classes branch out. This particular class helps you to catch any throwable errors, irrespective of whether they are an exception or an error. For example:

<?php
try {
    throw new Exception("This is an exception");
}
catch (Throwable $e) {
    echo $e->getMessage();
}

Or any of the newly defined ParseError:

<?php
try {
    $result = eval("2*'7'");
}
catch (Throwable $e) {
    echo $e->getMessage();
}

After executing this code, you will get a ParseError because “;” is missing inside eval().

Error Class

The error class in PHP 7 is a new type of class that handles the different error exceptions – either they are fatal errors or type errors. Error is divided into four subclasses:

  1. ArithmeticError
  2. TypeError
  3. ParseError
  4. AssertionError

The main thing to remember before upgrading to PHP 7 is that if you have defined a custom error class having name error in the versions before PHP 7, then you have to be sure that you have changed your custom error class name. If you have not done that, then you will get the Fatal Error.
Let’s discuss the above four classes one by one.

ArithmeticError

This error shows up when an error occurs while performing mathematical operations. For example, when you are using intdiv() in your function for some division, and after some calculation, a number is divided by 0 or -1, then an ArithmeticError will be thrown. Here is an example:

<?php
try {
    var_dump(intdiv(PHP_INT_MIN, -1));
}
catch (ArithmeticError $e) {
    echo $e->getMessage();
}

You will get “Division of PHP_INT_MIN by -1” because we have shifted it a bit by a negative amount.
Another class, DivisionByZeroError, also extends from ArithmeticError. This error is thrown on two different conditions:
Note: You will get -1 only in combination with PHP_INT_MIN.
First, if you do a modulus of a number by 0, DivisionByZeroError occurs, showing “Modulo by zero” error message:

<?php
try {
    $result = 5 % 0;
    echo $result;
}
catch (DivisionByZeroError $e) {
    echo $e->getMessage();
}

However, if you use the same method as above and change the % by /, you will get warning instead of exception and the result can be any one from these: +INF, -INF, or NAN . However, you will have the DivisionByZeroError exception if you execute the following code:

<?php
try {
    $result = is_finite(1.0 / 0);
    if (in_array($result, [INF, NAN,-INF])) {
        throw new DivisionByZeroError('Division by zero error');
    }
}
catch (DivisionByZeroError $e) {
    echo $e->getMessage();
}

The other method that will get you the DivisionByZeroError is by using intdiv().
Note: A bug report for this issue has been reported on PHP.net.

TypeError

This error is mostly used with the Scalar Type declarations in PHP 7. The error will be shown when you have created a function or variable of specific data type and you are trying to save a value of different data type. For example:

<?php
declare (strict_types = 1);
function add(int $a, int $b)
{
    return $a + $b;
}
try {
    echo add("3", "4");
}
catch (TypeError $e) {
    echo $e->getMessage();
}

If you run the above code, TypeError exception will be thrown and you will get “must be of the type integer, string was given” error, but if you run the above code without declare(strict_types=1); you won’t get any exception and the result will be 7 unless you change the number by a string like “name”.

ParseError

This error is thrown when you are using eval() function to insert a new line of code or using an external PHP file which contains a syntax error. Before the ParseError, when you have a syntax error in your external PHP file or in eval() function, your code is broken and a fatal error is shown. For example, let’s assume we have a PHP file having the following code:

<?php
$a = 4
$result = $a * 5;

And, we are calling it another PHP file:

<?php
try {
    require "index3.php";
}
catch (ParseError $e) {
    echo $e->getMessage();
}

When this code is executed, “syntax error, unexpected end of file” is shown instead of a fatal error. This class helps you in many conditions. For example, if you are sending some information to another file, after that information is sent your code will run and, if by mistake, you have sent an irrelevant data, then there is a high probability that your code will be broken. Before this class was introduced, it was almost impossible to handle the syntax and fatal errors with ease.

AssertionError

Before the introduction of the AssertionError class, we have to create our functions to handle assertion exceptions to handle fatal errors when you have binded your custom function using assert_options(). This error will only be shown when an assertion made via assert(), fails. To work with it, you first need to configure the assert directives in PHP.ini file. You need to turn on these 2 options according to your need.

  1. Assert.exception: By default, its value is 0 and it only generates warning for the object rather than showing the error. However, when the value is changed to 1, then it will throw you an exception or an Assertion Error, which can be caught by Throwable or AssertionError, itself.
  2. Zend.assertions: By default, it’s value is -1 which is for production mode, i.e., the assertion code will not be generated. When it is set to 1 it will be in development mode in which assertion code will be generated and executed. When it is set to 0, assertion code will be generated but won’t be executed in runtime.

For example, let’s make an assert which will fail.

<?php
try {
    assert(2 < 1, "Two is less than one");
}
catch (AssertionError $ex) {
    echo $ex->getMessage();
}

When the above code is executed, you will get only a warning that “assert(): Two is less than one failed” and your exception will not be caught because assert.exception is 0 and in order to make AssertionError catch the assert exception, we need to change assert.exception to 1. So when you run the following code:

<?php
ini_set('assert.exception', 1);
try {
    assert(2 < 1, "Two is not less than one");
}
catch (AssertionError $ex) {
    echo $ex->getMessage();
}

Instead of the warning, you will see that an exception is caught and only an exception message will be shown, i.e. “Two is less than one.”

Changes in Backward Compatibles:

Since the introduction of new classes, many of the fatal and recoverable fatal errors have been inherited from the Error class. It is not guaranteed that your custom handler, which you have set by using set_exception_handler(), will catch those errors. So, if you want to throw some custom exceptions during your program, you don’t have to set your custom handler as it will now catch the errors by just using ‘Throwable’.

Summary

If you are using a PHP version older than 7, than you should keep these things in mind before moving to PHP 7. You can also look at PHP 7 upgrade guide before upgrading from PHP previous versions.