Не прерывать ответ на ErrorException

Я пишу собственный обработчик ошибок для Slim/3.3.0 и пытаюсь выяснить, стоит ли повторно использовать один и тот же код для обработки как ошибок, так и исключений. Для этого я определил собственный обработчик ошибок для преобразования ошибок в экземпляры ErrorException:

require __DIR__ . '/../vendor/autoload.php';

set_error_handler (function ($errno, $errstr, $errfile, $errline) {
    if (!(error_reporting() & $errno)) {
        return true; // Do not run built-in handler
    }
    throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
});

$app = new \Slim\App(['settings' => ['displayErrorDetails' => false]]);
$container = $app->getContainer();
// [...]
$container['errorHandler'] = function (Slim\Container $c) {
    return new App\Handlers\Error($c->logger, $c['settings']['displayErrorDetails']);
};

Затем я могу регистрировать неперехваченные исключения и/или отображать мою общую страницу «Произошла ошибка» по своему вкусу (пока все хорошо).

Но теперь я хочу обрабатывать незначительные проблемы (E_WARNING, E_NOTICE и т. д.) по-другому: вместо того, чтобы прерывать все и показывать общий шаблон страницы ошибок, я хочу иметь возможность продолжить выполнение и/или отображать сообщение об ошибке inline< /em> (так же, как PHP по умолчанию), и здесь я потерялся. Часть отображать встроенный очень проста, но мои скрипты тут же обрываются:

namespace App\Handlers;

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;

final class Error extends \Slim\Handlers\Error
{
    public function __invoke(Request $request, Response $response, \Exception $e)
    {
        if ($this->displayErrorDetails) {
            $response->write($e);
        } else {
            $this->saveToLog($e);
            $response->write('[ERROR]');
        }

        if ($this->isFatal($e)) {
            // Aborts scripts and displays error page (OK)
            return parent::__invoke($request, $response, $e);
        } else {
            // Seems to abort script (nothing else is shown from this poing)
            return $response;
        }
    }
}

... проверяя это так:

$app->get('/warning-test', function (Request $request, Response $response) {
    $this->logger->info("Loading {$_SERVER['REQUEST_URI']}");
    $response->write('<h1>Warning test page</h1>');
    $response->write('<p>About to generate a warning:</p>');
    $this->logger->info("Generating warning...");
    1/0;
    $this->logger->info("Warning generated");

    $response->write('<p>This should display as well.</p>');
    // ... but it doesn't. Probably because Response is immutable and my copy
    // was superseded by a clone

    return $response;
});

Каковы мои варианты?


person Álvaro González    schedule 30.08.2016    source источник
comment
Как только обработчик ошибок вызывается, Slim останавливает выполнение... Нет никакого способа продолжить, о котором я знаю.   -  person geggleto    schedule 31.08.2016


Ответы (1)


Функция set_error_handler() принимает в качестве второго параметра тип ошибки, поэтому вы можете укажите, что только E_ERROR должен использовать ваш собственный обработчик ошибок:

$errorTypes = E_ERROR;
set_error_handler (function ($errno, $errstr, $errfile, $errline) {
    if (!(error_reporting() & $errno)) {
        return true; // Do not run built-in handler
    }
    throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
}, $errorTypes);

Если вы хотите самостоятельно обрабатывать уведомления и предупреждения, вы не можете генерировать исключение, поскольку оно в основном отменяет обычный маршрут и принимает только ответ об ошибке. Вы можете сделать это, не вызывая исключение, например:

$errorTypes = E_WARNING | E_NOTICE;
set_error_handler (function ($errno, $errstr, $errfile, $errline) {
    if (!(error_reporting() & $errno)) {
        return true; // Do not run built-in handler
    }
    \App\Handlers\Error::setNoticeOrWarning($errno, $errstr, $errfile, $errline);
}, $errorTypes);

Затем вы можете проверить это позже в промежуточном программном обеспечении и отобразить это.

person jmattheis    schedule 30.08.2016
comment
Однако это полностью пропустит мой пользовательский обработчик - person Álvaro González; 30.08.2016
comment
@ ÁlvaroGonzález Итак, вы хотите, чтобы уведомления и предупреждения по-прежнему обрабатывались в вашем пользовательском обработчике, но для их отображения использовалось поведение php по умолчанию? - person jmattheis; 31.08.2016
comment
Я хочу, чтобы они полностью обрабатывались моим пользовательским кодом. Просто я не хочу, чтобы мой объект Response был заменен. - person Álvaro González; 31.08.2016
comment
Спасибо. Как только вы обратили мое внимание на тот факт, что throw сам по себе прерывает нормальный поток, мне удалось заставить мой обработчик ошибок работать именно так, как я предполагал. - person Álvaro González; 01.09.2016