Exception Handling

Configuration

config/exception.php

return [
    // Configure the exception handling class here
    '' => support\exception\Handler::class,
];

In multi-application mode, you can configure an exception handling class for each application individually. Refer to multi-application.

Default Exception Handler Class

Exceptions in webman are handled by the support\exception\Handler class by default. You can modify the configuration file config/exception.php to change the default exception handler class. The exception handler class must implement the Webman\Exception\ExceptionHandlerInterface.

interface ExceptionHandlerInterface
{
    /**
     * Log the exception
     * @param Throwable $e
     * @return mixed
     */
    public function report(Throwable $e);

    /**
     * Render the response
     * @param Request $request
     * @param Throwable $e
     * @return Response
     */
    public function render(Request $request, Throwable $e) : Response;
}

Rendering Responses

The render method in the exception handler class is used to render the response.

If the debug value in the configuration file config/app.php is set to true (hereinafter referred to as app.debug=true), detailed exception information will be returned; otherwise, simplified exception information will be returned.

If the request expects a JSON response, the returned exception information will be in JSON format, similar to:

{
    "code": "500",
    "msg": "Exception information"
}

If app.debug=true, an additional trace field will be included in the JSON data, returning the detailed call stack.

You can write your own exception handler class to change the default exception handling logic.

Business Exception BusinessException

Sometimes we want to terminate the request in a nested function and return an error message to the client. We can achieve this by throwing a BusinessException. For example:

<?php
namespace app\controller;

use support\Request;
use support\exception\BusinessException;

class FooController
{
    public function index(Request $request)
    {
        $this->checkInput($request->post());
        return response('hello index');
    }

    protected function checkInput($input)
    {
        if (!isset($input['token'])) {
            throw new BusinessException('Parameter error', 3000);
        }
    }
}

The above example will return a

{"code": 3000, "msg": "Parameter error"}

Note
A BusinessException does not need to be caught with a try-catch in business logic, as the framework will automatically catch it and return an appropriate output based on the request type.

Custom Business Exception

If the above response does not meet your requirements, for example, if you want to change msg to message, you can customize a MyBusinessException.

Create a new file app/exception/MyBusinessException.php with the following content:

<?php

namespace app\exception;

use support\exception\BusinessException;
use Webman\Http\Request;
use Webman\Http\Response;

class MyBusinessException extends BusinessException
{
    public function render(Request $request): ?Response
    {
        // Return JSON data for JSON requests
        if ($request->expectsJson()) {
            return json(['code' => $this->getCode() ?: 500, 'message' => $this->getMessage()]);
        }
        // For non-JSON requests, return a page
        return new Response(200, [], $this->getMessage());
    }
}

Then when a business logic calls:

use app\exception\MyBusinessException;

throw new MyBusinessException('Parameter error', 3000);

JSON requests will receive a response similar to:

{"code": 3000, "message": "Parameter error"}

Tip
Since BusinessException is a business exception (for example, user input parameter errors), it is predictable. Therefore, the framework does not consider it a fatal error and will not log it.

Summary

Whenever you want to interrupt the current request and return information to the client, consider using the BusinessException exception.