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 exception handling

Your exception class needs to inherit from Swoft\Rpc\Server\Exception\Handler\AbstractRpcServerErrorHandler

After processing the exception, you must return a Swoft\Rpc\Server\Response object as a response to the rpc client.

Use example

This sample code comes from the app/Exception/Handler/RpcExceptionHandler swowt/swoft .

 <?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;
    }
} 

Instructions for use

 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