事與願違。你無法預測錯誤,但可以預期錯誤。每個 Slim Framework 應用程式都有一個接收所有未捕捉到的 PHP 例外的錯誤處理程式。這個錯誤處理程式也會收到目前的 HTTP 要求和回應物件。錯誤處理程式必須準備並傳回一個適當的 Response 物件,傳回到 HTTP 客戶端。
<?php
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
/**
* The routing middleware should be added earlier than the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled by the middleware
*/
$app->addRoutingMiddleware();
/**
* Add Error Middleware
*
* @param bool $displayErrorDetails -> Should be set to false in production
* @param bool $logErrors -> Parameter is passed to the default ErrorHandler
* @param bool $logErrorDetails -> Display error details in error log
* @param LoggerInterface|null $logger -> Optional PSR-3 Logger
*
* Note: This middleware should be added last. It will not handle any exceptions/errors
* for middleware added after it.
*/
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// ...
$app->run();
現在你可以為任何類型的 Exception 或 Throwable 映射自訂處理程式。
<?php
use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Log\LoggerInterface;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// Add Routing Middleware
$app->addRoutingMiddleware();
// Optional: Define custom error logger
$logger = new Logger('error');
$logger->pushHandler(new RotatingFileHandler('error.log'));
// Define Custom Error Handler
$customErrorHandler = function (
ServerRequestInterface $request,
Throwable $exception,
bool $displayErrorDetails,
bool $logErrors,
bool $logErrorDetails
) use ($app, $logger) {
if ($logger) {
$logger->error($exception->getMessage());
}
$payload = ['error' => $exception->getMessage()];
$response = $app->getResponseFactory()->createResponse();
$response->getBody()->write(
json_encode($payload, JSON_UNESCAPED_UNICODE)
);
return $response;
};
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger);
$errorMiddleware->setDefaultErrorHandler($customErrorHandler);
// ...
$app->run();
如果你想將自訂錯誤記錄導向附帶 Slim 的預設 ErrorHandler
,有兩種方法可以做到。
使用第一個方法,你可以直接延伸 ErrorHandler
並取消存根 logError()
方法。
<?php
namespace MyApp\Handlers;
use Slim\Handlers\ErrorHandler;
class MyErrorHandler extends ErrorHandler
{
protected function logError(string $error): void
{
// Insert custom error logging function.
}
}
<?php
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// Add Routing Middleware
$app->addRoutingMiddleware();
// Instantiate Your Custom Error Handler
$myErrorHandler = new MyErrorHandler($app->getCallableResolver(), $app->getResponseFactory());
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
$errorMiddleware->setDefaultErrorHandler($myErrorHandler);
// ...
$app->run();
使用第二個方法,你可以提供符合 PSR-3 標準 的記錄器,例如來自熱門 Monolog 函式庫的記錄器。
<?php
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// Add Routing Middleware
$app->addRoutingMiddleware();
// Monolog Example
$logger = new Logger('app');
$streamHandler = new StreamHandler(__DIR__ . '/var/log', 100);
$logger->pushHandler($streamHandler);
// Add Error Middleware with Logger
$errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger);
// ...
$app->run();
繪製最終從處理中脫鉤。它將繼續檢測內容類型並在 ErrorRenderers
的幫助下適當地繪製內容。核心 ErrorHandler
延伸 AbstractErrorHandler
類別,它已被徹底重新編組。預設情況下,它將呼叫適當的 ErrorRenderer
以取得支援的內容類型。核心 ErrorHandler
為下列內容類型定義繪製器
application/json
application/xml
和 text/xml
text/html
text/plain
對於任何內容類型,您都可以註冊自己的錯誤繪製器。所以首先定義一個新的錯誤繪製器,實作 \Slim\Interfaces\ErrorRendererInterface
。
<?php
use Slim\Interfaces\ErrorRendererInterface;
use Throwable;
class MyCustomErrorRenderer implements ErrorRendererInterface
{
public function __invoke(Throwable $exception, bool $displayErrorDetails): string
{
return 'My awesome format';
}
}
然後在核心錯誤處理程式中註冊該錯誤繪製器。在下面的範例中,我們將註冊繪製器以用於 text/html
內容類型。
<?php
use MyApp\Handlers\MyErrorHandler;
use Slim\Factory\AppFactory;
require __DIR__ . '/../vendor/autoload.php';
$app = AppFactory::create();
// Add Routing Middleware
$app->addRoutingMiddleware();
// Add Error Middleware
$errorMiddleware = $app->addErrorMiddleware(true, true, true);
// Get the default error handler and register my custom error renderer.
$errorHandler = $errorMiddleware->getDefaultErrorHandler();
$errorHandler->registerErrorRenderer('text/html', MyCustomErrorRenderer::class);
// ...
$app->run();
預設情況下,錯誤處理程式會試著使用要求的 Accept
標頭來檢測錯誤繪製器。如果您需要強制錯誤處理程式使用特定的錯誤繪製器,您可以撰寫以下內容。
$errorHandler->forceContentType('application/json');
我們在應用程式中加入已命名的 HTTP 例外。這些例外非常適合原生繪製器。它們各自可以有 description
和 title
屬性,當呼叫原生 HTML 繪製器時也能提供更多見解。
基底類別 HttpSpecializedException
延伸 Exception
,並附帶以下子類別
如果您需要任何其他一律回應代碼,而我們決定不提供基底存放庫,您可以延伸 HttpSpecializedException
類別。舉例來說,如果您想要一個類似原生超時錯誤的 504 網關逾時錯誤,您會執行以下操作:
class HttpGatewayTimeoutException extends HttpSpecializedException
{
protected $code = 504;
protected $message = 'Gateway Timeout.';
protected $title = '504 Gateway Timeout';
protected $description = 'Timed out before receiving response from the upstream server.';
}
若要觸發 HTTP 例外,請使用以下程式碼
use Slim\Exception\HttpNotFoundException;
// ...
throw new HttpNotFoundException($request);
確保當觸發例外時,傳遞了 $request
物件。