Manejo de Excepciones

Configuración

config/exception.php

return [
    // Aquí se configura la clase de manejo de excepciones
    '' => support\exception\Handler::class,
];

En el modo de múltiples aplicaciones, puedes configurar una clase de manejo de excepciones para cada aplicación por separado, consulta múltiples aplicaciones.

Clase de Manejo de Excepciones por Defecto

En webman, las excepciones son manejadas por defecto por la clase support\exception\Handler. Puedes modificar el archivo de configuración config/exception.php para cambiar la clase de manejo de excepciones por defecto. La clase de manejo de excepciones debe implementar la interfaz Webman\Exception\ExceptionHandlerInterface.

interface ExceptionHandlerInterface
{
    /**
     * Registrar logs
     * @param Throwable $e
     * @return mixed
     */
    public function report(Throwable $e);

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

Renderizar Respuesta

El método render en la clase de manejo de excepciones se utiliza para renderizar la respuesta.

Si el valor debug en el archivo de configuración config/app.php es true (de aquí en adelante app.debug=true), se devolverá información detallada sobre la excepción; de lo contrario, se devolverá información resumida sobre la excepción.

Si la solicitud espera una respuesta en formato json, la información de excepción se devolverá en formato json, como

{
    "code": "500",
    "msg": "Información de excepción"
}

Si app.debug=true, los datos json incluirán un campo adicional trace que devolverá la pila de llamadas detallada.

Puedes escribir tu propia clase de manejo de excepciones para cambiar la lógica de manejo de excepciones por defecto.

Excepción de Negocio BusinessException

A veces, queremos terminar una solicitud en una función anidada y devolver un mensaje de error al cliente; en este caso, podemos hacerlo lanzando una BusinessException.
Por ejemplo:

<?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('Error de parámetro', 3000);
        }
    }
}

El ejemplo anterior devolverá un

{"code": 3000, "msg": "Error de parámetro"}

Nota
La excepción de negocio BusinessException no necesita ser capturada en un try, el marco la capturará automáticamente y devolverá la salida adecuada según el tipo de solicitud.

Excepción de Negocio Personalizada

Si la respuesta anterior no se ajusta a tus necesidades, por ejemplo, si deseas cambiar msg a message, puedes personalizar una MyBusinessException.

Crea un nuevo archivo app/exception/MyBusinessException.php con el siguiente contenido

<?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
    {
        // Si la solicitud es json, devuelve datos json
        if ($request->expectsJson()) {
            return json(['code' => $this->getCode() ?: 500, 'message' => $this->getMessage()]);
        }
        // Para solicitudes no json, devuelve una página
        return new Response(200, [], $this->getMessage());
    }
}

Así, cuando el negocio llame

use app\exception\MyBusinessException;

throw new MyBusinessException('Error de parámetro', 3000);

la solicitud json recibirá una respuesta json similar a la siguiente

{"code": 3000, "message": "Error de parámetro"}

Sugerencia
Dado que la excepción BusinessException pertenece a excepciones de negocio (por ejemplo, error de parámetros de entrada del usuario), es predecible, por lo que el marco no la considera un error fatal y no registra logs.

Resumen

En cualquier momento que desees interrumpir la solicitud actual y devolver información al cliente, considera usar la excepción BusinessException.