Zend Framework 中 MVC 异常的捕获与处理

先来看一个正常的控制器前端的定义:

$front = Zend_Controller_Front::getInstance ();
$front->setBaseUrl ( '/' )
      ->setParam ( 'noViewRenderer', true )
      ->setControllerDirectory ( './application/modules/admin/controllers' )
      ->throwExceptions ( true )
      ->dispatch ();


第一行,获取控制器前端实例

第二行,设置 baseUrl

第三行,禁用ViewRenderer自动渲染

第四行,设置控制器目录

第五行,分发

这种模式下,如果访问一个URL中含有无效的 Controller 或 Action ,那么ZF就会抛出异常。于是,如何处理这种异常就非常有必要了。

ZF手册中也有相关的说明,只是没有给出完整的代码。在此,自己记录一下,也希望对其他的朋友能有所帮助。

 

方法一、通过 Zend_Controller_Front::throwExceptions()

如下代码段:

$front->setBaseUrl ( '/' )
      ->setParam ( 'noViewRenderer', true )
      ->setControllerDirectory ( './application/modules/admin/controllers' )
      ->throwExceptions ( true );

try{
      $front->dispatch();
} catch	(Exception $e) {
      echo '显示错误信息';
}


其中主要是 throwExceptions ( true ); 用于设置异常由开发人员来处理。

 

方法二、通过 Zend_Controller_Front::returnResponse() 和 Zend_Controller_Response_Abstract::isException()

如下代码段:

$front->setParam('noErrorHandler', true)
      ->throwExceptions(false)
      ->setControllerDirectory ( './application/modules/admin/controllers' )
      ->returnResponse(true);
      
$response = $front->dispatch();
 
if ($response->isException()) {
    $exceptions = $response->getException();
    echo handleException($exceptions[0]);
} else {
    echo $response;
}
 
function handleException(Exception $e)
{
    switch ($e->getCode()) {
        case 500: {
            if (!include_once('./resource/html/500.html')) {
                @header("HTTP/1.x 500 Internal Server Error");
                @header('Status: 500 Internal Server Error');
            }
            exit;
            break;
        }
 
        default: {
            if (!include_once('./resource/html/404.html')) {
                @header('HTTP/1.x 404 Not Found');
                @header('Status: 404 Not Found');
            }
            exit;
            break;

        }
    }
}


原理就是捕获异常的类型,然后重定向到错误页面。以上二种方法,都是通过控制器前端来实现的,而下面则是继承相应的类来实现。

 

方法三、继承 Zend_Controller_Action,并重写 __call() 方法

class My_Controller_Action extends Zend_Controller_Action
{
	public function __call($method,	$args)
	{
		if ('Action' == substr($method,	-6)) {
			$controller = $this->getRequest()->getControllerName();
			$url = '/' . $controller . '/index';
			return $this->_redirect($url);
		}

		throw new Exception('Invalid method');
	}
}


继承 Zend_Controller_Action 类,并重写魔术方法 __call(),然后所有的 Action 都继承这个子类,对于无效的 Action 就可以在 __call 里处理,比如可以重写向到一个错误页,也可以重定向到默认页。此处重定向到默认页。

 

方法五、继承 Zend_Controller_Dispatcher, 并重写 getAction()

class My_Controller_Dispatcher extends Zend_Controller_Dispatcher
{
	public function getAction($request)
	{
		$action = $request->getActionName();
		if (empty($action)) {
			$action	= $this->getDefaultAction();
			$request->setActionName($action);
			$action	= $this->formatActionName($action);
		} else {
			$controller	= $this->getController();
			$action		= $this->formatActionName($action);
			if (!method_exists($controller,	$action)) {
				$action	= $this->getDefaultAction();
				$request->setActionName($action);
				$action	= $this->formatActionName($action);
			}
		}

		return $action;
	}
}


分发器就是在用户请求数据时,先取得模块名、控制器名、动作名以及参数等,然后实例化相应的控件器,并调用相应动作的整个过程。

这里,去继承分发器类,就可以在“调用”动作时来设置来如何调用。如代码中的,先判断 Action 是否有效,有效就调用这个 Action,无效而设置成默认的Action。

继承后,就需要通知控制器前端,如下代码:

$myDispatcher = new My_Controller_Dispatcher();

$front->setDispatcher($myDispatcher);

这样就为系统设置了一个自己定义的分发器,并用此分发器处理无效的Action。

 

方法六、使用Zend_Controller_Action::preDispatch()或者Zend_Controller_Plugin_Abstract::preDispatch()来识别无效的动作。

class My_Controller_PreDispatchPlugin extends Zend_Controller_Plugin_Abstract
{
	public function preDispatch(Zend_Controller_Request_Abstract $request)
	{
		$dispatcher = Zend_Controller_Front::getInstance()->getDispatcher();
		$controller = $dispatcher->getController($request);
		if (!$controller) {
		         $controller = $dispatcher->getDefaultControllerName($request);
		}
		$action = $dispatcher->getAction($request);

		if (!method_exists($controller, $action)) {
			$defaultAction = $dispatcher->getDefaultAction();
			$controllerName = $request->getControllerName();
			$response = Zend_Controller_Front::getInstance()->getResponse();
			$response->setRedirect('/' . $controllerName . 
			                       '/' . $defaultAction);
			$response->sendHeaders();
			exit;
		}
	}
}
  preDispatch 是在分发之前调用,这里就是先判断 Controller 是否有效,如果无效就设置成默认的 Controller,然后再分发下去。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值