不要中止对 ErrorException 的响应
Do not abort response on 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']);
};
然后我可以记录未捕获的异常 and/or 根据我的喜好显示我的通用 "There was an error" 页面(到目前为止还不错)。
但现在我想以不同的方式处理小问题(E_WARNING
、E_NOTICE
等):我希望能够继续,而不是中止一切并显示一般错误页面模板执行 and/or 显示错误消息 inline(就像 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);
然后你可以稍后在中间件中检查并显示它。
我正在为 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']);
};
然后我可以记录未捕获的异常 and/or 根据我的喜好显示我的通用 "There was an error" 页面(到目前为止还不错)。
但现在我想以不同的方式处理小问题(E_WARNING
、E_NOTICE
等):我希望能够继续,而不是中止一切并显示一般错误页面模板执行 and/or 显示错误消息 inline(就像 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);
然后你可以稍后在中间件中检查并显示它。