1

在使用 Zend 1 框架的 PHP webapp 上,如果代码抛出异常,我会得到一个很好的错误页面,其中包含我的品牌等。

如果代码遇到 PHP 致命错误(例如,当对象引用意外地为空时,“方法调用非对象”),那么我只会得到一个 Apache 500 错误页面。

在后一种情况下,如何获得一个不错的错误页面?

我尝试过的事情:

  • 如果设置了 PHP ini“display_errors”,那么我只会收到纯文本形式的致命错误消息
  • 如果没有设置“display_errors”,那么我会得到 Apache 默认的 500 错误页面
  • 在这种情况下,Apache“ErrorDocument”指令似乎被忽略了
4

2 回答 2

2

如果这可以帮助任何人,我可以通过一些技巧获得完整的 Zend 错误页面(带有应用程序布局),以在出现致命错误的情况下显示。

希望有一个更简单的方法来做到这一点。如果是这样,请在您的替代方案中添加答案。

将此添加到引导程序:

  /**
   * Sets up a register_shutdown_function hook to give a nice error page when a
   * PHP fatal error is encountered.
   */
  protected function _initFatalErrorCatcher()
  {
      register_shutdown_function(array($this, 'onApplicationShutdown'));
  }

  public function onApplicationShutdown()
  {
      $error = error_get_last();
      $wasFatal = ($error && ($error['type'] === E_ERROR) || ($error['type'] === E_USER_ERROR));
      if ($wasFatal)
      {
          $frontController = Zend_Controller_Front::getInstance();
          $errorHandler = $frontController->getPlugin('Zend_Controller_Plugin_ErrorHandler');
          $request = $frontController->getRequest();
          $response = $frontController->getResponse();

          // Add the fatal exception to the response in a format that ErrorHandler will understand
          $response->setException(new Exception(
              "Fatal error: $error[message] at $error[file]:$error[line]",
              $error['type']));

          // Call ErrorHandler->_handleError which will forward to the Error controller
          $handleErrorMethod = new ReflectionMethod('Zend_Controller_Plugin_ErrorHandler', '_handleError');
          $handleErrorMethod->setAccessible(true);
          $handleErrorMethod->invoke($errorHandler, $request);

          // Discard any view output from before the fatal
          ob_end_clean();

          // Now display the error controller:
          $frontController->dispatch($request, $response);
      }
  }

您需要一个自定义路由器类来帮助:

class My_Router_Rewrite extends Zend_Controller_Router_Rewrite
{
    public function route(Zend_Controller_Request_Abstract $request)
    {
        // If the ErrorHandler plugin has stashed the error in a request param, then
        // it will have already dealt with routing (see Bootstrap::onApplicationShutdown())
        // (Note that this param cannot be spoofed, since any user-supplied params
        // will be strings, not objects)
        if (is_object($request->getParam('error_handler'))) {
            return $request;
        } else {
            return parent::route($request);
        }
    }
}

(确保此类在引导程序中注册为您的路由器)

于 2013-04-29T17:02:22.420 回答
1

类似于以前的解决方案,但不需要重写路由器。

在 Bootstrap.php 中:

public function __construct($application) {
    parent::__construct($application);

    // handle PHP errors
    Core_Error_Handler::set();
}

Core/Error/Handler.php 类:

class Core_Error_Handler {

    public static function handle() {

        if(!$error = error_get_last()) {
            return;
        }

        $frontController = Zend_Controller_Front::getInstance();
        $request = $frontController->getRequest();
        $response = $frontController->getResponse();

        $response->setException(new Exception("Fatal error: $error[message] at $error[file]:$error[line]",$error['type']));

        // this clean what is before the error
        ob_end_clean();

        $frontController->dispatch($request, $response);
    }

    public static function set(){
        register_shutdown_function(array(__CLASS__, 'handle'));
    }
} 
于 2014-06-06T21:39:02.420 回答