2021-03-31 18:19:43 +08:00
# Excepiton Handler
2019-06-04 19:09:36 +08:00
2021-03-31 18:19:43 +08:00
In `Hyperf` , all the business code excute on `Worker Process` . In this case, once any request has an exception that has not been caught, the corresponding `Worker Process` will be interrupted and exited, which is unacceptable for the service. Catch exceptions and output reasonable error content is also more friendly to the client. We can define different `ExceptionHandlers` for each `server` , and once there are exceptions that are not caught in the process, they will be passed to the registered `ExceptionHandler` for processing.
2019-06-04 19:09:36 +08:00
2021-03-31 18:19:43 +08:00
## Customize an Exception Handling
2019-06-24 11:13:47 +08:00
2021-03-31 18:19:43 +08:00
### Register Exception Handler
2019-06-04 19:09:36 +08:00
2021-03-31 18:19:43 +08:00
Currently, it only supports the registration of `ExceptionHandler` in the form of a configuration file. The configuration file is located in `config/autoload/exceptions.php` . Configure your custom exception handler under the corresponding `server` :
2019-06-04 19:09:36 +08:00
```php
< ?php
// config/autoload/exceptions.php
return [
'handler' => [
2021-03-31 18:19:43 +08:00
// The http here corresponds to the name value corresponding to the server in config/autoload/server.php
2019-06-04 19:09:36 +08:00
'http' => [
2021-03-31 18:19:43 +08:00
// The registration of the exception handler has done by configuring the complete class namespace address here
2019-06-25 11:38:11 +08:00
\App\Exception\Handler\FooExceptionHandler::class,
2019-06-04 19:09:36 +08:00
],
],
];
```
2021-03-31 18:19:43 +08:00
> The order of each exception handler configuration array determines the order in which exceptions are passed between handlers.
2019-06-04 19:09:36 +08:00
2021-03-31 18:19:43 +08:00
### Define Exception Handler
2019-06-04 19:09:36 +08:00
2021-03-31 18:19:43 +08:00
We can define a `class (Class)` anywhere and inherit the abstract class `Hyperf\ExceptionHandler\ExceptionHandler` and implement the abstract methods in it. As shown below:
2019-06-04 19:09:36 +08:00
```php
< ?php
2019-06-24 01:19:38 +08:00
namespace App\Exception\Handler;
2019-06-04 19:09:36 +08:00
2019-06-24 01:19:38 +08:00
use Hyperf\ExceptionHandler\ExceptionHandler;
2019-06-04 19:09:36 +08:00
use Hyperf\HttpMessage\Stream\SwooleStream;
2019-06-04 19:31:25 +08:00
use Psr\Http\Message\ResponseInterface;
2019-06-25 11:38:11 +08:00
use App\Exception\FooException;
2019-06-04 19:09:36 +08:00
use Throwable;
2019-06-25 11:38:11 +08:00
class FooExceptionHandler extends ExceptionHandler
2019-06-04 19:09:36 +08:00
{
public function handle(Throwable $throwable, ResponseInterface $response)
{
2021-03-31 18:19:43 +08:00
// Determine that the caught exception is the wanted exception
2019-06-25 11:38:11 +08:00
if ($throwable instanceof FooException) {
2021-03-31 18:19:43 +08:00
// Formatted output
2019-06-04 19:09:36 +08:00
$data = json_encode([
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
], JSON_UNESCAPED_UNICODE);
2019-06-24 17:28:13 +08:00
2021-03-31 18:19:43 +08:00
// Prevent bubbling
2019-06-24 17:28:13 +08:00
$this->stopPropagation();
2019-06-04 19:09:36 +08:00
return $response->withStatus(500)->withBody(new SwooleStream($data));
}
2019-06-24 11:13:47 +08:00
2021-03-31 18:19:43 +08:00
// Hand over to the next exception handler
return $response;
2019-06-24 17:28:13 +08:00
2021-03-31 18:19:43 +08:00
// Or directly shield the exception without processing
2019-06-04 19:09:36 +08:00
}
2019-06-24 01:19:38 +08:00
2019-06-26 18:01:25 +08:00
/**
2021-03-31 18:19:43 +08:00
* Determine whether the exception handler needs to handle the exception or not
2019-06-26 18:01:25 +08:00
*/
2019-06-24 01:19:38 +08:00
public function isValid(Throwable $throwable): bool
{
return true;
}
2019-06-04 19:09:36 +08:00
}
```
2021-03-31 18:19:43 +08:00
### Define Exception Class
2019-06-24 11:13:47 +08:00
2019-06-24 01:19:38 +08:00
```php
< ?php
2019-06-24 11:13:47 +08:00
namespace App\Exception;
2019-06-24 01:19:38 +08:00
2019-06-24 11:13:47 +08:00
use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
2019-06-24 01:19:38 +08:00
use Throwable;
2019-06-25 11:38:11 +08:00
class FooException extends ServerException
2019-06-24 01:19:38 +08:00
{
}
```
2021-03-31 18:19:43 +08:00
### Trigger Exception
2019-06-24 11:13:47 +08:00
2019-06-24 01:19:38 +08:00
```php
2019-06-24 11:13:47 +08:00
namespace App\Controller;
2019-06-24 01:19:38 +08:00
2019-06-26 18:01:25 +08:00
use App\Exception\FooException;
2019-06-24 12:54:25 +08:00
2021-03-31 18:19:43 +08:00
class IndexController extends AbstractController
2019-06-24 11:13:47 +08:00
{
2019-06-24 01:19:38 +08:00
public function index()
{
2019-06-25 11:38:11 +08:00
throw new FooException('Foo Exception...', 800);
2019-06-24 01:19:38 +08:00
}
2019-06-24 11:13:47 +08:00
}
2019-06-24 01:19:38 +08:00
```
2021-03-31 18:19:43 +08:00
In the example above, we assume that `FooException` is a thrown exception, and exception handlers are configured. When an uncaught exception has been thrown, it will be passed through the handler registration order. Imagine the processing as a pipe, the exception will not be passed once there are some handler calls `$this->stopPropagation()` . The default handler of Hyperf will be the last one to catch exceptions if there is no other handler to catch such exceptions.
## Integrated Whoops
The framework provides Whoops integration.
Install Whoops first
```php
composer require --dev filp/whoops
```
Then configure the special exception handler for Whoops.
```php
// config/autoload/exceptions.php
return [
'handler' => [
'http' => [
\Hyperf\ExceptionHandler\Handler\WhoopsExceptionHandler::class,
],
],
];
```
As shown in the image:
![whoops ](/imgs/whoops.png )
## Error Listener
The framework provides the `error_reporting()` error level listener `Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler` .
### Configuration
Add a listener in `config/autoload/listeners.php`
```php
< ?php
return [
\Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class
];
```
When a code similar to the following appears, `\ErrorException` will be thrown
```php
< ?php
try {
$a = [];
var_dump($a[1]);
} catch (\Throwable $throwable) {
var_dump(get_class($throwable), $throwable->getMessage());
}
// string(14) "ErrorException"
// string(19) "Undefined offset: 1"
```
If no listener is configured, no exception will be thrown.
```
PHP Notice: Undefined offset: 1 in IndexController.php on line 24
Notice: Undefined offset: 1 in IndexController.php on line 24
NULL
```