Exception handling

From the previous introduction we know that the exception handling in swowt is to divide the scene.

In several general-purpose servers, we have built-in basic exception handling classes for the corresponding scenes.

annotation

The annotation tag Swoft\Error\Annotation\Mapping\ExceptionHandler provided by the swoft-error component provides the tag for the exception handler class.

ExceptionHandler annotation

@ExceptionHandler marks a class as an exception handler

Have attributes:

  • exceptions defines the exception class to be processed, the full class name is required

Matching logic

In the same scenario, multiple processors can be defined to handle different exceptions.

  • When an exception occurs, the exception class is first used to find the processor. If the match is successful, it will be processed by it.
  • If the complete match fails, it will check if the exception class is a subclass of the registered exception class, and it is to select the first matching processor to process.
  • If the match still fails, it will be processed by the system by default.

Http Request exception handling

Your exception class needs to inherit from Swoft\Http\Server\Exception\Handler\AbstractHttpErrorHandler

After processing the exception you must return a Swoft\Http\Message\Response object as a response to the http client.

Use example

This sample code comes from swowt/swoft app/Exception/Handler/HttpExceptionHandler

<?php declare(strict_types=1);

namespace App\Exception\Handler;

use const APP_DEBUG;
use function get_class;
use ReflectionException;
use function sprintf;
use Swoft\Bean\Exception\ContainerException;
use Swoft\Error\Annotation\Mapping\ExceptionHandler;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Exception\Handler\AbstractHttpErrorHandler;
use Throwable;

/**
 * Class HttpExceptionHandler
 *
 * @ExceptionHandler(\Throwable::class)
 */
class HttpExceptionHandler extends AbstractHttpErrorHandler
{
    /**
     * @param Throwable $e
     * @param Response   $response
     *
     * @return Response
     * @throws ReflectionException
     * @throws ContainerException
     */
    public function handle(Throwable $e, Response $response): Response
    {
        // Debug is false
        if (!APP_DEBUG) {
            return $response->withStatus(500)->withContent(
                sprintf(' %s At %s line %d', $e->getMessage(), $e->getFile(), $e->getLine())
            );
        }

        $data = [
            'code'  => $e->getCode(),
            'error' => sprintf('(%s) %s', get_class($e), $e->getMessage()),
            'file'  => sprintf('At %s line %d', $e->getFile(), $e->getLine()),
            'trace' => $e->getTraceAsString(),
        ];

        // Debug is true
        return $response->withData($data);
    }
}

RPC 异常处理

你的异常类需要继承 Swoft\Rpc\Server\Exception\Handler\AbstractRpcServerErrorHandler

在处理异常后你必须返回一个 Swoft\Rpc\Server\Response 对象作为对rpc客户端的响应。

使用示例

这个示例代码来自 swoft/swoftapp/Exception/Handler/RpcExceptionHandler

<?php declare(strict_types=1);

namespace App\Exception\Handler;

use ReflectionException;
use Swoft\Bean\Exception\ContainerException;
use Swoft\Error\Annotation\Mapping\ExceptionHandler;
use Swoft\Log\Debug;
use Swoft\Rpc\Error;
use Swoft\Rpc\Server\Exception\Handler\RpcErrorHandler;
use Swoft\Rpc\Server\Response;
use Throwable;

/**
 * Class RpcExceptionHandler
 *
 * @since 2.0
 *
 * @ExceptionHandler(\Throwable::class)
 */
class RpcExceptionHandler extends RpcErrorHandler
{
    /**
     * @param Throwable $e
     * @param Response  $response
     *
     * @return Response
     * @throws ReflectionException
     * @throws ContainerException
     */
    public function handle(Throwable $e, Response $response): Response
    {
        // Debug is false
        if (!APP_DEBUG) {
            $message = sprintf(' %s At %s line %d', $e->getMessage(), $e->getFile(), $e->getLine());
            $error   = Error::new($e->getCode(), $message, null);
        } else {
            $error = Error::new($e->getCode(), $e->getMessage(), null);
        }

        Debug::log('Rpc server error(%s)', $e->getMessage());

        $response->setError($error);

        // Debug is true
        return $response;
    }
}

使用说明

class BusinessLogic 
{
    public function doSomething()
    {
        throw new BusinessException("Error Processing Request", 500);
    }
}

When an exception is thrown here:

  • It is handled by the HttpExceptionHandler within the scope of the http request scene.
  • If it is in the RPC server request scenario, it will be handled by RpcExceptionHandler .

The above handler is found by looking up the exception parent class. Of course, you can also define an exception handler @ExceptionHandler(BusinessException::class) for BusinessException .

Conclusion

From the above example we can see that even if you are throwing an exception in the same place, as long as you define an exception handler for a different scene. It is possible to separately request different scenarios (such as http and rpc above), and return different responses without additional checks and judgments.

The exception handling for more scenarios can also be written with reference to the example above.

/docs/2.x/en/error/usage.html
progress-bar