现在的位置: 首页 > 综合 > 正文

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

2018年05月19日 ⁄ 综合 ⁄ 共 3626字 ⁄ 字号 评论关闭

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

$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,然后再分发下去。

抱歉!评论已关闭.