10.2. 异常模式

application.dispatcher.catchException(配置文件, 或者可通过Yaf_Dispatcher::catchException(true))开启的情况下, 当Yaf遇到未捕获异常的时候, 就会把运行权限, 交给当前模块的Error Controller的Error Action动作, 而异常或作为请求的一个参数, 传递给Error Action.

在Error Action中可以通过$request->getRequest()->getParam("exception")获取当前发生的异常.

[重要] 重要
从Yaf1.0.0.12开始, 也可以通过$request->getException()来获取当前发生的异常, 而如果Error Action定义了一个名为$exception的参数的话, 也可以直接通过这个参数获取当前发生的异常.

例 10.1. Error Controller

     
<?php

/**
 * 当有未捕获的异常, 则控制流会流到这里
 */
class ErrorController extends Yaf_Controller_Abstract {
 /**
  * 也可通过$request->getException()获取到发生的异常
  */
        public function errorAction($exception) {
      assert($exception === $exception->getCode());
      $this->getView()->assign("code", $exception->getCode());
      $this->getView()->assign("message", $exception->getMessage());
        }
     
    


有了这样的最终异常处理逻辑, 应用就可以在出错的时候直接抛出异常, 在统一异常处理逻辑中, 根据各种不同的异常逻辑, 处理错误, 记录日志. 一个常用的Error Action如下:

例 10.2.

     
<?php

/**
 * 当有未捕获的异常, 则控制流会流到这里
 */
class ErrorController extends Yaf_Controller_Abstract {
 /**
  * 也可通过$request->getException()获取到发生的异常
  */
        public function errorAction($exception) {
  switch($exception->getCode()) {
      case YAF_ERR_LOADFAILD:
      case YAF_ERR_LOADFAILD_MODULE:
      case YAF_ERR_LOADFAILD_CONTROLLER:
      case YAF_ERR_LOADFAILD_ACTION:
      //404
      header("Not Found");
      break;

      case CUSTOM_ERROR_CODE:
      //自定义的异常
      ....
      break;
  }
        }
    
    


当然, 一个更为易读的方式:

例 10.3.

     
<?php

/**
 * 当有未捕获的异常, 则控制流会流到这里
 */
class ErrorController extends Yaf_Controller_Abstract {
 /**
  * 此时可通过$request->getException()获取到发生的异常
  */
        public function errorAction() {
  $exception = $this->getRequest()->getException();
  try {
    throw $exception;
  } catch (Yaf_Exception_LoadFailed $e) {
    //加载失败
  } catch (Yaf_Exception $e) {
    //其他错误
  }
        }
    
    


自定义错误处理

如果不使用上面的模式, 也可以通过Yaf_Dispatcher::setErrorHandler注册一个错误处理器, 在发生错误时拿到具体的错误信息. 一个例子:

例 10.4. 注册错误处理器


<?php
function error_handler($errno, $errstr, $errfile, $errline) {
   var_dump(Yaf_Application::app()->getLastErrorNo());
   var_dump(Yaf_Application::app()->getLastErrorNo() == YAF_ERR_NOTFOUND_CONTROLLER);
}

$config = array(
  "application" => array(
   "directory" => "/tmp/notexists",
     "dispatcher" => array(
       "throwException" => 0, //发生错误时触发错误而不是抛出异常
      ),
  ),
);

$app = new Yaf_Application($config);
$app->getDispatcher()->setErrorHandler("error_handler", E_RECOVERABLE_ERROR);
$app->run();
?>



以上例程的输出类似于:


int(516)
bool(true)