hyperf/docs/en/exception-handler.md

174 lines
4.9 KiB
Markdown

# Excepiton Handler
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.
## Customize an Exception Handling
### Register Exception Handler
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`:
```php
<?php
// config/autoload/exceptions.php
return [
'handler' => [
// The http here corresponds to the name value corresponding to the server in config/autoload/server.php
'http' => [
// The registration of the exception handler has done by configuring the complete class namespace address here
\App\Exception\Handler\FooExceptionHandler::class,
],
],
];
```
> The order of each exception handler configuration array determines the order in which exceptions are passed between handlers.
### Define Exception Handler
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:
```php
<?php
namespace App\Exception\Handler;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use App\Exception\FooException;
use Throwable;
class FooExceptionHandler extends ExceptionHandler
{
public function handle(Throwable $throwable, ResponseInterface $response)
{
// Determine that the caught exception is the wanted exception
if ($throwable instanceof FooException) {
// Formatted output
$data = json_encode([
'code' => $throwable->getCode(),
'message' => $throwable->getMessage(),
], JSON_UNESCAPED_UNICODE);
// Prevent bubbling
$this->stopPropagation();
return $response->withStatus(500)->withBody(new SwooleStream($data));
}
// Hand over to the next exception handler
return $response;
// Or directly shield the exception without processing
}
/**
* Determine whether the exception handler needs to handle the exception or not
*/
public function isValid(Throwable $throwable): bool
{
return true;
}
}
```
### Define Exception Class
```php
<?php
namespace App\Exception;
use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;
class FooException extends ServerException
{
}
```
### Trigger Exception
```php
namespace App\Controller;
use App\Exception\FooException;
class IndexController extends AbstractController
{
public function index()
{
throw new FooException('Foo Exception...', 800);
}
}
```
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
```