如何使用Zend Framework之分发器_Controller Dispatcher?

如何使用Zend Framework之分发器_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类,基于标准分发器来修改功能。

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

希望本文所述对大家PHP程序设计有所帮助。