Unnoticed Things about PHP Exception & Error
Tags: php, errors, exception
Published: 2020-05-20 17:13:26

Do you know:
+ What's `Throwable`, what's the difference between `Throwable` and `Exception` 
+ Can `try-catch` catch all exceptions and errors in php?
+ What kind of error or exception can't be catched by `try-catch`? And how to deal with these errors?
+ Can `set_error_handler()` handle all errors? 
+ How many types of error in PHP? And what's the difference between them?

### `Throwable`
Since PHP7, `Error` class was introduced for fatal but recoverable errors, it could be caught like any other exception, but it does not extend `Exception` class. To unites these two classes, `Error` and `Exception` both implement `Throwable` interface.
For more information, [click here](https://trowski.com/2015/06/24/throwable-exceptions-and-errors-in-php7/)
![PHP_7_exception_hierarchy](https://shakalakab.github.io/images/PHP_7_exception_hierarchy.png)

### Can `try-catch` catch all exceptions and errors in php?
Of course no. The exceptions and errors that work in `try-catch` would not be beyond `Error` and `Exception` categories. And as above explains, `Error` is only thrown when fatal but recoverable errors happen, so warning error and notice error won't work in `try-catch`.

As following code shows, we call on an undefined function, which would cause an fatal error, throw an `Error`. Cause `Error` is not a subclass of `Exception`, but it implements `Throwable`, so it would be caught by `catch(Throwable $e)` not `catch (Exception $e)`.
```
try {
    $var = 1;
    $var->method();
} catch (Exception $e) {
      echo "Exception type: " . get_class($e) . "\n";
      echo 'Exception message: ' . $e->getMessage() . "\n";
} catch (Throwable $e) {
    echo "Error type: " . get_class($e) . "\n";
    echo 'Error message: ' . $e->getMessage() . "\n";
}
```
But what if we just call on an undefined variable, which throws an notice error?
```
try {
    $var = 1;
    echo $a;
} catch (Exception $e) {
      echo "Exception type: " . get_class($e) . "\n";
      echo 'Exception message: ' . $e->getMessage() . "\n";
} catch (Throwable $e) {
    echo "Error type: " . get_class($e) . "\n";
    echo 'Error message: ' . $e->getMessage() . "\n";
}
```
Execute above code, the notice error is thrown and not caught, so `try-catch` does not work for notice error.

### Can `set_error_handler()` handle all errors?
Of course no. `set_error_handler()` is used to set user defined error handler function, which would work for `trigger_error`. But the thing we don't notice is that it works for warning error and notice error as well, and `error_reporting()` has no effect for it. According to [PHP manual](https://www.php.net/manual/en/function.set-error-handler.php), `set_error_handler()` cannot handle **E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING**.
```
error_reporting(7); // error_reporting() won't work while set_error_handler is set
set_error_handler(function ($level, $message, $file = '', $line = 0, $context = []) {
    echo "level: $level\n";
    echo "msg: $message\n";
    echo "file: $file\n";
    echo "line: $line\n";
});

$arr = ['b' => 'c'];
$arr['a'];
```
As above example shows, we call on an undefined variable, which causes notice error, and this error would be caught by `set_error_handler()`. Although we set `error_reporting(7)`, which means the level beyond 7 won't be reported, `set_error_handler()` disable it. Level of notice error reporting is 8, without `set_error_handler`, the notice error won't be thrown.  

### How many types of error in PHP?
Basically, four types. Notice error, warning error, parse error and fatal error. The first two can't be dealt with `try-catch`, not included in `Error`, can be handled by `set_error_handler()`. On the contrary, some of the last two can be handled by `try-catch`, and not by `set_error_handler()`.
For more details: [click here](https://phoenixnap.com/kb/php-error-types)