Я пишу собственный обработчик ошибок для 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
и т. д.) по-другому: вместо того, чтобы прервать все и показать шаблон страницы с общей ошибкой, я хочу продолжить выполнение и / или отобразить сообщение об ошибке в соответствии (так же, как 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;
});
Какие у меня варианты?
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);
Затем вы можете проверить это позже в промежуточном программном обеспечении и отобразить это.
Других решений пока нет …