例外処理

設定

config/exception.php

return [
    // ここで例外処理クラスを設定します
    '' => support\exception\Handler::class,
];

マルチアプリケーションモードの場合は、各アプリケーションごとに例外処理クラスを個別に設定できます。詳細はマルチアプリケーションを参照してください。

デフォルト例外処理クラス

webmanでは、例外はデフォルトで support\exception\Handler クラスによって処理されます。デフォルトの例外処理クラスを変更するには、設定ファイルconfig/exception.phpを修正してください。例外処理クラスはWebman\Exception\ExceptionHandlerInterface インターフェースを実装する必要があります。

interface ExceptionHandlerInterface
{
    /**
     * ログの記録
     * @param Throwable $e
     * @return mixed
     */
    public function report(Throwable $e);

    /**
     * レンダリング応答
     * @param Request $request
     * @param Throwable $e
     * @return Response
     */
    public function render(Request $request, Throwable $e) : Response;
}

レンダリング応答

例外処理クラスのrenderメソッドは応答をレンダリングするために使用されます。

設定ファイルconfig/app.phpdebug値がtrueの場合(以下 app.debug=true)、詳細な例外情報が返されます。そうでない場合は、簡略な例外情報が返されます。

もしリクエストがjsonでの応答を期待している場合、返される例外情報はjson形式で返され、次のようになります。

{
    "code": "500",
    "msg": "例外情報"
}

app.debug=trueの場合、jsonデータには追加のtraceフィールドが含まれ、詳細なコールスタックが返されます。

独自の例外処理クラスを作成して、デフォルトの例外処理ロジックを変更することができます。

ビジネス例外 BusinessException

時には、特定のネストした関数内でリクエストを中断し、エラーメッセージをクライアントに返したい場合があります。その場合、BusinessExceptionをスローすることでこれを実現できます。
例えば:

<?php
namespace app\controller;

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

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

    protected function chackInpout($input)
    {
        if (!isset($input['token'])) {
            throw new BusinessException('パラメータエラー', 3000);
        }
    }
}

上記の例は次のような応答を返します。

{"code": 3000, "msg": "パラメータエラー"}

注意
ビジネス例外BusinessExceptionはビジネスにおいてtryで捕捉する必要はなく、フレームワークが自動で捕捉し、リクエストの種類に応じた適切な出力を返します。

カスタムビジネス例外

上記の応答がニーズに合わない場合、例えばmsgmessageに変更したい場合、MyBusinessExceptionをカスタム作成できます。

新たにapp/exception/MyBusinessException.phpを作成し、内容は次のようにします。

<?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
    {
        // jsonリクエストはjsonデータを返します
        if ($request->expectsJson()) {
            return json(['code' => $this->getCode() ?: 500, 'message' => $this->getMessage()]);
        }
        // 非jsonリクエストの場合はページを返します
        return new Response(200, [], $this->getMessage());
    }
}

このように、ビジネスロジックで次のように呼び出すと

use app\exception\MyBusinessException;

throw new MyBusinessException('パラメータエラー', 3000);

jsonリクエストは次のようなjson応答を受け取ります。

{"code": 3000, "message": "パラメータエラー"}

ヒント
BusinessException例外はビジネス例外(例えばユーザーの入力パラメータエラー)に属するため、予測可能であり、フレームワークはこれを致命的なエラーとは見なさず、ログを記録しません。

まとめ

現在のリクエストを中断し、情報をクライアントに返す必要がある場合はBusinessException例外の使用を考慮してください。