Slim 4自定义错误页如何添加菜单并复用布局?
自定义错误页复用Slim框架现有布局与避免PHP默认错误页方案
我已经查阅了Slim框架自定义错误中间件的文档,现在不清楚如何用PhpRenderer(或其他兼容Slim的渲染器)在自定义错误页中复用现有布局和菜单,有没有人实现过类似功能?
现有代码实现
渲染器实例化代码
$this->renderer = new PhpRenderer(__DIR__ . '/template'); $this->renderer->setLayout("layout.php"); $this->renderer->addAttribute('csrf', $this->getCrossSiteRequestForgeryPreventionToken()); $this->renderer->addAttribute('flash', $this->getFlashMessages()); $this->renderer->addAttribute('html', new HTMLHelper($this->renderer));
错误处理中间件配置代码
$errorMiddleware = $application->addErrorMiddleware($this->getConfiguration()->isDisplayingErrors(), $logErrors = true, $logErrorDetails = true); $errorHandler = $errorMiddleware->getDefaultErrorHandler(); $errorHandler->registerErrorRenderer('text/html', ErrorRenderer::class);
自定义ErrorRenderer类代码
use Slim\Exception\HttpNotFoundException; use Slim\Interfaces\ErrorRendererInterface; use Throwable; class ErrorRenderer implements ErrorRendererInterface { public function __invoke(Throwable $exception, bool $displayErrorDetails):string{ $title = 'Error'; $message = 'An error has occurred.'; $trace = ''; if ($exception instanceof HttpNotFoundException) { $title = 'Page not found'; $message = 'This page could not be found.'; } if ($displayErrorDetails){ $message = $exception->getMessage(); $trace = $exception->getTraceAsString(); } return $this->renderHtmlPage($title, $message, $trace); } public function renderHtmlPage(string $title='', string $message='', string $trace=''):string { $title = htmlentities($title, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8'); $message = htmlentities($message, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8'); $trace = htmlentities($trace, ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8'); $trace = preg_replace('%&NewLine;%usD', '<br/>', $trace); return <<<EOT <!DOCTYPE html> <html> <head> <title>$title - My website</title> </head> <body> <h1>$title</h1> <p>$message</p> <p>$trace</p> </body> </html> EOT; } }
我的需求:至少可以复用HTMLHelper,用$html->addText(...)替代直接调用htmlentities,但更希望能直接复用现有布局。另外还有一个问题:如果所有错误处理流程都失败,当php.ini配置允许时会回退到PHP默认错误页,有没有办法避免这种情况?
解决方案一:复用现有PhpRenderer与布局
核心思路是让ErrorRenderer拿到已配置好的PhpRenderer实例,通过构造函数注入实现复用:
- 修改
ErrorRenderer类,注入PhpRenderer:
use Slim\Exception\HttpNotFoundException; use Slim\Interfaces\ErrorRendererInterface; use Slim\Views\PhpRenderer; use Throwable; class ErrorRenderer implements ErrorRendererInterface { private PhpRenderer $renderer; // 注入已配置好的PhpRenderer public function __construct(PhpRenderer $renderer) { $this->renderer = $renderer; } public function __invoke(Throwable $exception, bool $displayErrorDetails):string{ $data = [ 'title' => 'Error', 'message' => 'An error has occurred.', 'trace' => '' ]; if ($exception instanceof HttpNotFoundException) { $data['title'] = 'Page not found'; $data['message'] = 'This page could not be found.'; } if ($displayErrorDetails){ $data['message'] = $exception->getMessage(); $data['trace'] = nl2br(htmlentities($exception->getTraceAsString(), ENT_NOQUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'utf-8')); } // 渲染错误模板,自动应用已设置的layout.php return $this->renderer->render('error.php', $data); } }
- 创建
error.php模板(放在/template目录下):
<h1><?= $this->e($title) ?></h1> <p><?= $this->e($message) ?></p> <?php if ($trace): ?> <div class="trace"><?= $trace ?></div> <?php endif; ?>
- 修改错误渲染器注册逻辑,传入已配置的PhpRenderer:
$errorHandler->registerErrorRenderer('text/html', function () { return new ErrorRenderer($this->renderer); });
这样错误页会自动应用现有layout.php,csrf、flash、html等属性也能在模板中正常使用,可直接用$html->addText(...)处理内容。
解决方案二:避免回退到PHP默认错误页
从PHP配置和框架兜底两个层面处理:
PHP配置层面:
- 在php.ini中设置:
display_errors = Off html_errors = Off - 或在应用入口文件顶部动态设置:
ini_set('display_errors', '0'); ini_set('html_errors', '0');
- 在php.ini中设置:
Slim框架层面:
- 确保错误中间件是第一个被添加的中间件,捕获尽可能多的错误:
// 先添加错误中间件,再添加其他中间件 $errorMiddleware = $application->addErrorMiddleware(...); // 再添加路由、认证等中间件 - 注册全局错误处理函数兜底:
// 转换PHP错误为Throwable set_error_handler(function ($errno, $errstr, $errfile, $errline) { throw new ErrorException($errstr, 0, $errno, $errfile, $errline); }); // 处理未捕获的异常 set_exception_handler(function (Throwable $e) { http_response_code(500); echo '<!DOCTYPE html><html><head><title>Server Error</title></head><body><h1>Server Error</h1><p>An unexpected error occurred.</p></body></html>'; exit; });
- 确保错误中间件是第一个被添加的中间件,捕获尽可能多的错误:
通过以上设置,即使Slim错误处理流程失效,也会输出自定义错误页,不会回退到PHP默认页面。
内容的提问来源于stack exchange,提问作者inf3rno
相关产品推荐
相关产品推荐

