php教程

超轻量级php框架startmvc

Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解

更新时间:2020-03-08 01:18:28 作者:startmvc
本文实例讲述了ZendFramework教程之分发器Zend_Controller_Dispatcher用法。分享给大家供大家参考,

本文实例讲述了Zend Framework教程之分发器Zend_Controller_Dispatcher用法。分享给大家供大家参考,具体如下:

分发器的具体实现

Zend Framework的分发器Zend_Controller_Dispatcher设计主要有,如下类和接口组成:

├── Dispatcher │   ├── Abstract.php │   ├── Exception.php │   ├── Interface.php │   └── Standard.php

Zend_Controller_Dispatcher_Interface

定义了分发器提供的基本和标准功能。


interface Zend_Controller_Dispatcher_Interface
{
 public function formatControllerName($unformatted);
 public function formatModuleName($unformatted);
 public function formatActionName($unformatted);
 public function isDispatchable(Zend_Controller_Request_Abstract $request);
 public function setParam($name, $value);
 public function setParams(array $params);
 public function getParam($name);
 public function getParams();
 public function clearParams($name = null);
 public function setResponse(Zend_Controller_Response_Abstract $response = null);
 public function getResponse();
 public function addControllerDirectory($path, $args = null);
 public function setControllerDirectory($path);
 public function getControllerDirectory();
 public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response);
 public function isValidModule($module);
 public function getDefaultModule();
 public function getDefaultControllerName();
 public function getDefaultAction();
}

Zend_Controller_Dispatcher_Abstract

实现了Zend_Controller_Dispatcher_Interface接口,提供了分发器提供的基本和标准功能的抽象父类。


<?php
/** Zend_Controller_Dispatcher_Interface */
require_once 'Zend/Controller/Dispatcher/Interface.php';
abstract class Zend_Controller_Dispatcher_Abstract implements Zend_Controller_Dispatcher_Interface
{
 protected $_defaultAction = 'index';
 protected $_defaultController = 'index';
 protected $_defaultModule = 'default';
 protected $_frontController;
 protected $_invokeParams = array();
 protected $_pathDelimiter = '_';
 protected $_response = null;
 protected $_wordDelimiter = array('-', '.');
 public function __construct(array $params = array())
 {
 $this->setParams($params);
 }
 public function formatControllerName($unformatted)
 {
 return ucfirst($this->_formatName($unformatted)) . 'Controller';
 }
 public function formatActionName($unformatted)
 {
 $formatted = $this->_formatName($unformatted, true);
 return strtolower(substr($formatted, 0, 1)) . substr($formatted, 1) . 'Action';
 }
 public function _verifyDelimiter($spec)
 {
 if (is_string($spec)) {
 return (array) $spec;
 } elseif (is_array($spec)) {
 $allStrings = true;
 foreach ($spec as $delim) {
 if (!is_string($delim)) {
 $allStrings = false;
 break;
 }
 }
 if (!$allStrings) {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Word delimiter array must contain only strings');
 }
 return $spec;
 }
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Invalid word delimiter');
 }
 public function getWordDelimiter()
 {
 return $this->_wordDelimiter;
 }
 public function setWordDelimiter($spec)
 {
 $spec = $this->_verifyDelimiter($spec);
 $this->_wordDelimiter = $spec;
 return $this;
 }
 public function getPathDelimiter()
 {
 return $this->_pathDelimiter;
 }
 public function setPathDelimiter($spec)
 {
 if (!is_string($spec)) {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Invalid path delimiter');
 }
 $this->_pathDelimiter = $spec;
 return $this;
 }
 protected function _formatName($unformatted, $isAction = false)
 {
 // preserve directories
 if (!$isAction) {
 $segments = explode($this->getPathDelimiter(), $unformatted);
 } else {
 $segments = (array) $unformatted;
 }
 foreach ($segments as $key => $segment) {
 $segment = str_replace($this->getWordDelimiter(), ' ', strtolower($segment));
 $segment = preg_replace('/[^a-z0-9 ]/', '', $segment);
 $segments[$key] = str_replace(' ', '', ucwords($segment));
 }
 return implode('_', $segments);
 }
 public function getFrontController()
 {
 if (null === $this->_frontController) {
 require_once 'Zend/Controller/Front.php';
 $this->_frontController = Zend_Controller_Front::getInstance();
 }
 return $this->_frontController;
 }
 public function setFrontController(Zend_Controller_Front $controller)
 {
 $this->_frontController = $controller;
 return $this;
 }
 public function setParam($name, $value)
 {
 $name = (string) $name;
 $this->_invokeParams[$name] = $value;
 return $this;
 }
 public function setParams(array $params)
 {
 $this->_invokeParams = array_merge($this->_invokeParams, $params);
 return $this;
 }
 public function getParam($name)
 {
 if(isset($this->_invokeParams[$name])) {
 return $this->_invokeParams[$name];
 }
 return null;
 }
 public function getParams()
 {
 return $this->_invokeParams;
 }
 public function clearParams($name = null)
 {
 if (null === $name) {
 $this->_invokeParams = array();
 } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
 unset($this->_invokeParams[$name]);
 } elseif (is_array($name)) {
 foreach ($name as $key) {
 if (is_string($key) && isset($this->_invokeParams[$key])) {
 unset($this->_invokeParams[$key]);
 }
 }
 }
 return $this;
 }
 public function setResponse(Zend_Controller_Response_Abstract $response = null)
 {
 $this->_response = $response;
 return $this;
 }
 public function getResponse()
 {
 return $this->_response;
 }
 public function setDefaultControllerName($controller)
 {
 $this->_defaultController = (string) $controller;
 return $this;
 }
 public function getDefaultControllerName()
 {
 return $this->_defaultController;
 }
 public function setDefaultAction($action)
 {
 $this->_defaultAction = (string) $action;
 return $this;
 }
 public function getDefaultAction()
 {
 return $this->_defaultAction;
 }
 public function setDefaultModule($module)
 {
 $this->_defaultModule = (string) $module;
 return $this;
 }
 public function getDefaultModule()
 {
 return $this->_defaultModule;
 }
}

Zend_Controller_Dispatcher_Standard

ZendFramework继承抽象类Zend_Controller_Dispatcher_Abstract,定义了Zend_Controller_Dispatcher_Standard。Zend_Controller_Dispatcher_Standard是ZendFramework提供的基本的分发器,完成了分发功能。


<?php
/** Zend_Loader */
require_once 'Zend/Loader.php';
/** Zend_Controller_Dispatcher_Abstract */
require_once 'Zend/Controller/Dispatcher/Abstract.php';
class Zend_Controller_Dispatcher_Standard extends Zend_Controller_Dispatcher_Abstract
{
 protected $_curDirectory;
 protected $_curModule;
 protected $_controllerDirectory = array();
 public function __construct(array $params = array())
 {
 parent::__construct($params);
 $this->_curModule = $this->getDefaultModule();
 }
 public function addControllerDirectory($path, $module = null)
 {
 if (null === $module) {
 $module = $this->_defaultModule;
 }
 $module = (string) $module;
 $path = rtrim((string) $path, '/\\');
 $this->_controllerDirectory[$module] = $path;
 return $this;
 }
 public function setControllerDirectory($directory, $module = null)
 {
 $this->_controllerDirectory = array();
 if (is_string($directory)) {
 $this->addControllerDirectory($directory, $module);
 } elseif (is_array($directory)) {
 foreach ((array) $directory as $module => $path) {
 $this->addControllerDirectory($path, $module);
 }
 } else {
 require_once 'Zend/Controller/Exception.php';
 throw new Zend_Controller_Exception('Controller directory spec must be either a string or an array');
 }
 return $this;
 }
 public function getControllerDirectory($module = null)
 {
 if (null === $module) {
 return $this->_controllerDirectory;
 }
 $module = (string) $module;
 if (array_key_exists($module, $this->_controllerDirectory)) {
 return $this->_controllerDirectory[$module];
 }
 return null;
 }
 public function removeControllerDirectory($module)
 {
 $module = (string) $module;
 if (array_key_exists($module, $this->_controllerDirectory)) {
 unset($this->_controllerDirectory[$module]);
 return true;
 }
 return false;
 }
 public function formatModuleName($unformatted)
 {
 if (($this->_defaultModule == $unformatted) && !$this->getParam('prefixDefaultModule')) {
 return $unformatted;
 }
 return ucfirst($this->_formatName($unformatted));
 }
 public function formatClassName($moduleName, $className)
 {
 return $this->formatModuleName($moduleName) . '_' . $className;
 }
 public function classToFilename($class)
 {
 return str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
 }
 public function isDispatchable(Zend_Controller_Request_Abstract $request)
 {
 $className = $this->getControllerClass($request);
 if (!$className) {
 return false;
 }
 $finalClass = $className;
 if (($this->_defaultModule != $this->_curModule)
 || $this->getParam('prefixDefaultModule'))
 {
 $finalClass = $this->formatClassName($this->_curModule, $className);
 }
 if (class_exists($finalClass, false)) {
 return true;
 }
 $fileSpec = $this->classToFilename($className);
 $dispatchDir = $this->getDispatchDirectory();
 $test = $dispatchDir . DIRECTORY_SEPARATOR . $fileSpec;
 return Zend_Loader::isReadable($test);
 }
 public function dispatch(Zend_Controller_Request_Abstract $request, Zend_Controller_Response_Abstract $response)
 {
 $this->setResponse($response);
 /**
 * Get controller class
 */
 if (!$this->isDispatchable($request)) {
 $controller = $request->getControllerName();
 if (!$this->getParam('useDefaultControllerAlways') && !empty($controller)) {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Invalid controller specified (' . $request->getControllerName() . ')');
 }
 $className = $this->getDefaultControllerClass($request);
 } else {
 $className = $this->getControllerClass($request);
 if (!$className) {
 $className = $this->getDefaultControllerClass($request);
 }
 }
 /**
 * Load the controller class file
 */
 $className = $this->loadClass($className);
 /**
 * Instantiate controller with request, response, and invocation
 * arguments; throw exception if it's not an action controller
 */
 $controller = new $className($request, $this->getResponse(), $this->getParams());
 if (!($controller instanceof Zend_Controller_Action_Interface) &&
 !($controller instanceof Zend_Controller_Action)) {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception(
 'Controller "' . $className . '" is not an instance of Zend_Controller_Action_Interface'
 );
 }
 /**
 * Retrieve the action name
 */
 $action = $this->getActionMethod($request);
 /**
 * Dispatch the method call
 */
 $request->setDispatched(true);
 // by default, buffer output
 $disableOb = $this->getParam('disableOutputBuffering');
 $obLevel = ob_get_level();
 if (empty($disableOb)) {
 ob_start();
 }
 try {
 $controller->dispatch($action);
 } catch (Exception $e) {
 // Clean output buffer on error
 $curObLevel = ob_get_level();
 if ($curObLevel > $obLevel) {
 do {
 ob_get_clean();
 $curObLevel = ob_get_level();
 } while ($curObLevel > $obLevel);
 }
 throw $e;
 }
 if (empty($disableOb)) {
 $content = ob_get_clean();
 $response->appendBody($content);
 }
 // Destroy the page controller instance and reflection objects
 $controller = null;
 }
 public function loadClass($className)
 {
 $finalClass = $className;
 if (($this->_defaultModule != $this->_curModule)
 || $this->getParam('prefixDefaultModule'))
 {
 $finalClass = $this->formatClassName($this->_curModule, $className);
 }
 if (class_exists($finalClass, false)) {
 return $finalClass;
 }
 $dispatchDir = $this->getDispatchDirectory();
 $loadFile = $dispatchDir . DIRECTORY_SEPARATOR . $this->classToFilename($className);
 if (Zend_Loader::isReadable($loadFile)) {
 include_once $loadFile;
 } else {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Cannot load controller class "' . $className . '" from file "' . $loadFile . "'");
 }
 if (!class_exists($finalClass, false)) {
 require_once 'Zend/Controller/Dispatcher/Exception.php';
 throw new Zend_Controller_Dispatcher_Exception('Invalid controller class ("' . $finalClass . '")');
 }
 return $finalClass;
 }
 public function getControllerClass(Zend_Controller_Request_Abstract $request)
 {
 $controllerName = $request->getControllerName();
 if (empty($controllerName)) {
 if (!$this->getParam('useDefaultControllerAlways')) {
 return false;
 }
 $controllerName = $this->getDefaultControllerName();
 $request->setControllerName($controllerName);
 }
 $className = $this->formatControllerName($controllerName);
 $controllerDirs = $this->getControllerDirectory();
 $module = $request->getModuleName();
 if ($this->isValidModule($module)) {
 $this->_curModule = $module;
 $this->_curDirectory = $controllerDirs[$module];
 } elseif ($this->isValidModule($this->_defaultModule)) {
 $request->setModuleName($this->_defaultModule);
 $this->_curModule = $this->_defaultModule;
 $this->_curDirectory = $controllerDirs[$this->_defaultModule];
 } else {
 require_once 'Zend/Controller/Exception.php';
 throw new Zend_Controller_Exception('No default module defined for this application');
 }
 return $className;
 }
 public function isValidModule($module)
 {
 if (!is_string($module)) {
 return false;
 }
 $module = strtolower($module);
 $controllerDir = $this->getControllerDirectory();
 foreach (array_keys($controllerDir) as $moduleName) {
 if ($module == strtolower($moduleName)) {
 return true;
 }
 }
 return false;
 }
 public function getDefaultControllerClass(Zend_Controller_Request_Abstract $request)
 {
 $controller = $this->getDefaultControllerName();
 $default = $this->formatControllerName($controller);
 $request->setControllerName($controller)
 ->setActionName(null);
 $module = $request->getModuleName();
 $controllerDirs = $this->getControllerDirectory();
 $this->_curModule = $this->_defaultModule;
 $this->_curDirectory = $controllerDirs[$this->_defaultModule];
 if ($this->isValidModule($module)) {
 $found = false;
 if (class_exists($default, false)) {
 $found = true;
 } else {
 $moduleDir = $controllerDirs[$module];
 $fileSpec = $moduleDir . DIRECTORY_SEPARATOR . $this->classToFilename($default);
 if (Zend_Loader::isReadable($fileSpec)) {
 $found = true;
 $this->_curDirectory = $moduleDir;
 }
 }
 if ($found) {
 $request->setModuleName($module);
 $this->_curModule = $this->formatModuleName($module);
 }
 } else {
 $request->setModuleName($this->_defaultModule);
 }
 return $default;
 }
 public function getDispatchDirectory()
 {
 return $this->_curDirectory;
 }
 public function getActionMethod(Zend_Controller_Request_Abstract $request)
 {
 $action = $request->getActionName();
 if (empty($action)) {
 $action = $this->getDefaultAction();
 $request->setActionName($action);
 }
 return $this->formatActionName($action);
 }
}

前端控制器和分发器


<?php
/** Zend_Loader */
require_once 'Zend/Loader.php';
/** Zend_Controller_Action_HelperBroker */
require_once 'Zend/Controller/Action/HelperBroker.php';
/** Zend_Controller_Plugin_Broker */
require_once 'Zend/Controller/Plugin/Broker.php';
class Zend_Controller_Front
{
 protected $_baseUrl = null;
 protected $_controllerDir = null;
 protected $_dispatcher = null;
 protected static $_instance = null;
 protected $_invokeParams = array();
 protected $_moduleControllerDirectoryName = 'controllers';
 protected $_plugins = null;
 protected $_request = null;
 protected $_response = null;
 protected $_returnResponse = false;
 protected $_router = null;
 protected $_throwExceptions = false;
 protected function __construct()
 {
 $this->_plugins = new Zend_Controller_Plugin_Broker();
 }
 private function __clone()
 {
 }
 public static function getInstance()
 {
 if (null === self::$_instance) {
 self::$_instance = new self();
 }
 return self::$_instance;
 }
 public function resetInstance()
 {
 $reflection = new ReflectionObject($this);
 foreach ($reflection->getProperties() as $property) {
 $name = $property->getName();
 switch ($name) {
 case '_instance':
 break;
 case '_controllerDir':
 case '_invokeParams':
 $this->{$name} = array();
 break;
 case '_plugins':
 $this->{$name} = new Zend_Controller_Plugin_Broker();
 break;
 case '_throwExceptions':
 case '_returnResponse':
 $this->{$name} = false;
 break;
 case '_moduleControllerDirectoryName':
 $this->{$name} = 'controllers';
 break;
 default:
 $this->{$name} = null;
 break;
 }
 }
 Zend_Controller_Action_HelperBroker::resetHelpers();
 }
 public static function run($controllerDirectory)
 {
 self::getInstance()
 ->setControllerDirectory($controllerDirectory)
 ->dispatch();
 }
 public function addControllerDirectory($directory, $module = null)
 {
 $this->getDispatcher()->addControllerDirectory($directory, $module);
 return $this;
 }
 public function setControllerDirectory($directory, $module = null)
 {
 $this->getDispatcher()->setControllerDirectory($directory, $module);
 return $this;
 }
 public function getControllerDirectory($name = null)
 {
 return $this->getDispatcher()->getControllerDirectory($name);
 }
 public function removeControllerDirectory($module)
 {
 return $this->getDispatcher()->removeControllerDirectory($module);
 }
 public function addModuleDirectory($path)
 {
 try{
 $dir = new DirectoryIterator($path);
 } catch(Exception $e) {
 require_once 'Zend/Controller/Exception.php';
 throw new Zend_Controller_Exception("Directory $path not readable", 0, $e);
 }
 foreach ($dir as $file) {
 if ($file->isDot() || !$file->isDir()) {
 continue;
 }
 $module = $file->getFilename();
 // Don't use SCCS directories as modules
 if (preg_match('/^[^a-z]/i', $module) || ('CVS' == $module)) {
 continue;
 }
 $moduleDir = $file->getPathname() . DIRECTORY_SEPARATOR . $this->getModuleControllerDirectoryName();
 $this->addControllerDirectory($moduleDir, $module);
 }
 return $this;
 }
 public function getModuleDirectory($module = null)
 {
 if (null === $module) {
 $request = $this->getRequest();
 if (null !== $request) {
 $module = $this->getRequest()->getModuleName();
 }
 if (empty($module)) {
 $module = $this->getDispatcher()->getDefaultModule();
 }
 }
 $controllerDir = $this->getControllerDirectory($module);
 if ((null === $controllerDir) || !is_string($controllerDir)) {
 return null;
 }
 return dirname($controllerDir);
 }
 public function setModuleControllerDirectoryName($name = 'controllers')
 {
 $this->_moduleControllerDirectoryName = (string) $name;
 return $this;
 }
 public function getModuleControllerDirectoryName()
 {
 return $this->_moduleControllerDirectoryName;
 }
 public function setDefaultControllerName($controller)
 {
 $dispatcher = $this->getDispatcher();
 $dispatcher->setDefaultControllerName($controller);
 return $this;
 }
 public function getDefaultControllerName()
 {
 return $this->getDispatcher()->getDefaultControllerName();
 }
 public function setDefaultAction($action)
 {
 $dispatcher = $this->getDispatcher();
 $dispatcher->setDefaultAction($action);
 return $this;
 }
 public function getDefaultAction()
 {
 return $this->getDispatcher()->getDefaultAction();
 }
 public function setDefaultModule($module)
 {
 $dispatcher = $this->getDispatcher();
 $dispatcher->setDefaultModule($module);
 return $this;
 }
 public function getDefaultModule()
 {
 return $this->getDispatcher()->getDefaultModule();
 }
 public function setRequest($request)
 {
 ...........................
 return $this;
 }
 public function getRequest()
 {
 return $this->_request;
 }
 public function setRouter($router)
 {
 ....................
 return $this;
 }
 public function getRouter()
 {
 ..................
 return $this->_router;
 }
 public function setBaseUrl($base = null)
 {
 ..............
 return $this;
 }
 public function getBaseUrl()
 {
 return $this->_baseUrl;
 }
 /**
 * Set the dispatcher object. The dispatcher is responsible for
 * taking a Zend_Controller_Dispatcher_Token object, instantiating the controller, and
 * call the action method of the controller.
 *
 * @param Zend_Controller_Dispatcher_Interface $dispatcher
 * @return Zend_Controller_Front
 */
 public function setDispatcher(Zend_Controller_Dispatcher_Interface $dispatcher)
 {
 $this->_dispatcher = $dispatcher;
 return $this;
 }
 /**
 * Return the dispatcher object.
 *
 * @return Zend_Controller_Dispatcher_Interface
 */
 public function getDispatcher()
 {
 /**
 * Instantiate the default dispatcher if one was not set.
 */
 if (!$this->_dispatcher instanceof Zend_Controller_Dispatcher_Interface) {
 require_once 'Zend/Controller/Dispatcher/Standard.php';
 $this->_dispatcher = new Zend_Controller_Dispatcher_Standard();
 }
 return $this->_dispatcher;
 }
 public function setResponse($response)
 {..................
 return $this;
 }
 public function getResponse()
 {
 return $this->_response;
 }
 public function setParam($name, $value)
 {
 $name = (string) $name;
 $this->_invokeParams[$name] = $value;
 return $this;
 }
 public function setParams(array $params)
 {
 $this->_invokeParams = array_merge($this->_invokeParams, $params);
 return $this;
 }
 public function getParam($name)
 {
 if(isset($this->_invokeParams[$name])) {
 return $this->_invokeParams[$name];
 }
 return null;
 }
 public function getParams()
 {
 return $this->_invokeParams;
 }
 public function clearParams($name = null)
 {
 if (null === $name) {
 $this->_invokeParams = array();
 } elseif (is_string($name) && isset($this->_invokeParams[$name])) {
 unset($this->_invokeParams[$name]);
 } elseif (is_array($name)) {
 foreach ($name as $key) {
 if (is_string($key) && isset($this->_invokeParams[$key])) {
 unset($this->_invokeParams[$key]);
 }
 }
 }
 return $this;
 }
 public function registerPlugin(Zend_Controller_Plugin_Abstract $plugin, $stackIndex = null)
 {
 $this->_plugins->registerPlugin($plugin, $stackIndex);
 return $this;
 }
 public function unregisterPlugin($plugin)
 {
 $this->_plugins->unregisterPlugin($plugin);
 return $this;
 }
 public function hasPlugin($class)
 {
 return $this->_plugins->hasPlugin($class);
 }
 public function getPlugin($class)
 {
 return $this->_plugins->getPlugin($class);
 }
 public function getPlugins()
 {
 return $this->_plugins->getPlugins();
 }
 public function throwExceptions($flag = null)
 {
 .....................
 return $this->_throwExceptions;
 }
 public function returnResponse($flag = null)
 {
 ................
 return $this->_returnResponse;
 }
 /**
 * Dispatch an HTTP request to a controller/action.
 *
 * @param Zend_Controller_Request_Abstract|null $request
 * @param Zend_Controller_Response_Abstract|null $response
 * @return void|Zend_Controller_Response_Abstract Returns response object if returnResponse() is true
 */
 public function dispatch(Zend_Controller_Request_Abstract $request = null, Zend_Controller_Response_Abstract $response = null)
 {
 if (!$this->getParam('noErrorHandler') && !$this->_plugins->hasPlugin('Zend_Controller_Plugin_ErrorHandler')) {
 // Register with stack index of 100
 require_once 'Zend/Controller/Plugin/ErrorHandler.php';
 $this->_plugins->registerPlugin(new Zend_Controller_Plugin_ErrorHandler(), 100);
 }
 if (!$this->getParam('noViewRenderer') && !Zend_Controller_Action_HelperBroker::hasHelper('viewRenderer')) {
 require_once 'Zend/Controller/Action/Helper/ViewRenderer.php';
 Zend_Controller_Action_HelperBroker::getStack()->offsetSet(-80, new Zend_Controller_Action_Helper_ViewRenderer());
 }
 /**
 * Instantiate default request object (HTTP version) if none provided
 */
 if (null !== $request) {
 $this->setRequest($request);
 } elseif ((null === $request) && (null === ($request = $this->getRequest()))) {
 require_once 'Zend/Controller/Request/Http.php';
 $request = new Zend_Controller_Request_Http();
 $this->setRequest($request);
 }
 /**
 * Set base URL of request object, if available
 */
 if (is_callable(array($this->_request, 'setBaseUrl'))) {
 if (null !== $this->_baseUrl) {
 $this->_request->setBaseUrl($this->_baseUrl);
 }
 }
 /**
 * Instantiate default response object (HTTP version) if none provided
 */
 if (null !== $response) {
 $this->setResponse($response);
 } elseif ((null === $this->_response) && (null === ($this->_response = $this->getResponse()))) {
 require_once 'Zend/Controller/Response/Http.php';
 $response = new Zend_Controller_Response_Http();
 $this->setResponse($response);
 }
 /**
 * Register request and response objects with plugin broker
 */
 $this->_plugins
 ->setRequest($this->_request)
 ->setResponse($this->_response);
 /**
 * Initialize router
 */
 $router = $this->getRouter();
 $router->setParams($this->getParams());
 /**
 * Initialize dispatcher
 */
 $dispatcher = $this->getDispatcher();
 $dispatcher->setParams($this->getParams())
 ->setResponse($this->_response);
 // Begin dispatch
 try {
 /**
 * Route request to controller/action, if a router is provided
 */
 /**
 * Notify plugins of router startup
 */
 $this->_plugins->routeStartup($this->_request);
 try {
 $router->route($this->_request);
 } catch (Exception $e) {
 if ($this->throwExceptions()) {
 throw $e;
 }
 $this->_response->setException($e);
 }
 /**
 * Notify plugins of router completion
 */
 $this->_plugins->routeShutdown($this->_request);
 /**
 * Notify plugins of dispatch loop startup
 */
 $this->_plugins->dispatchLoopStartup($this->_request);
 /**
 * Attempt to dispatch the controller/action. If the $this->_request
 * indicates that it needs to be dispatched, move to the next
 * action in the request.
 */
 do {
 $this->_request->setDispatched(true);
 /**
 * Notify plugins of dispatch startup
 */
 $this->_plugins->preDispatch($this->_request);
 /**
 * Skip requested action if preDispatch() has reset it
 */
 if (!$this->_request->isDispatched()) {
 continue;
 }
 /**
 * Dispatch request
 */
 try {
 $dispatcher->dispatch($this->_request, $this->_response);
 } catch (Exception $e) {
 if ($this->throwExceptions()) {
 throw $e;
 }
 $this->_response->setException($e);
 }
 /**
 * Notify plugins of dispatch completion
 */
 $this->_plugins->postDispatch($this->_request);
 } while (!$this->_request->isDispatched());
 } catch (Exception $e) {
 if ($this->throwExceptions()) {
 throw $e;
 }
 $this->_response->setException($e);
 }
 /**
 * Notify plugins of dispatch loop completion
 */
 try {
 $this->_plugins->dispatchLoopShutdown();
 } catch (Exception $e) {
 if ($this->throwExceptions()) {
 throw $e;
 }
 $this->_response->setException($e);
 }
 if ($this->returnResponse()) {
 return $this->_response;
 }
 $this->_response->sendResponse();
 }
}

以上对Zend_Controller_Front和Zend_Controller_Dispatcher做了简单的标记,通过分析代码不难看出,基本的运行机制。

分发发生在前端控制器中的一个循环(loop)中。分发之前,前端控制器通过路由请求,找到用户指定的模块、控制器、动作和可选参数。然后进入分发循环,分发请求。

分发器需要大量数据完成任务——它需要知道如何格式化控制器和动作的名称,到哪儿找到控制器类文件,模块名是否有效,以及基于其它可用信息判定请求是否能分发的API。

每次迭代(iteration)过程开始时,在请求对象中设置一个标志指示该动作已分发。如果在动作或者前/后分发(pre/postDispatch)插件重置了该标志,分发循环将继续下去并试图分发新的请求。通过改变请求中的控制器或者动作并重置已分发标志,开发人员可以定制执行一个请求链。

控制这种分发过程的动作控制器方法是_forward();在任意的pre/postDispatch()或者动作中调用该方法,并传入动作、控制器、模块、以及可选的附加参数,就可以进入新的动作。

自定义分发器

Zend_Controller_Dispatcher_Interface定义了下列所有分发器需要实现的方法。

不过大多数情况下,只需要简单地扩展抽象类Zend_Controller_Dispatcher_Abstract,其中已经定义好了上面的大部分方法。或者扩展Zend_Controller_Dispatcher_Standard类,基于标准分发器来修改功能。

需要子类化分发器的可能原因包括:期望在动作控制器中使用不同的类和方法命名模式,或者期望使用不同的分发方式,比如分发到控制器目录下的动作文件,而不是控制器类的动作方法。

Zend Framework 分发器 Zend_Controller_Dispatcher