You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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('%
%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实例,通过构造函数注入实现复用:

  1. 修改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);
    }
}
  1. 创建error.php模板(放在/template目录下):
<h1><?= $this->e($title) ?></h1>
<p><?= $this->e($message) ?></p>
<?php if ($trace): ?>
    <div class="trace"><?= $trace ?></div>
<?php endif; ?>
  1. 修改错误渲染器注册逻辑,传入已配置的PhpRenderer:
$errorHandler->registerErrorRenderer('text/html', function () {
    return new ErrorRenderer($this->renderer);
});

这样错误页会自动应用现有layout.php,csrf、flash、html等属性也能在模板中正常使用,可直接用$html->addText(...)处理内容。


解决方案二:避免回退到PHP默认错误页

从PHP配置和框架兜底两个层面处理:

  1. PHP配置层面:

    • 在php.ini中设置:
      display_errors = Off
      html_errors = Off
      
    • 或在应用入口文件顶部动态设置:
      ini_set('display_errors', '0');
      ini_set('html_errors', '0');
      
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 01:52:40