不要在ErrorException

时间:2016-08-30 09:35:40

标签: php error-handling slim psr-7

我正在为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_WARNINGE_NOTICE等):我希望能够继续执行并且不会中止所有内容并显示通用错误页面模板/或显示错误消息 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;
});

我有什么选择?

1 个答案:

答案 0 :(得分: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);

然后您可以稍后在中间件中查看此内容并显示此内容。