目录
Zend_Controller是使用MVC模式来构建一个站点的基础。Zend_Controller体系是一个轻量的,模块化和可扩展的体系。它只提供最核心的必要的部分,允许开发者有很大的自由来灵活地构建自己的站点。使用Zend_Controller的站点,其文件组织和代码结构会比较相似。
			Zend_Controller 的工作流(workflow)是通过几个组件来实现的。虽然不需要完全理解这几个组件的含义,如果你对工作流程有点了解是很有帮助的。
			
						Zend_Controller_Front是Zend_Controller_Controller体系的组织者,它是FrontController设计模式的实现。Zend_Controller_Front处理服务器接受的所有请求,并最后负责将请求分配给各个ActionController(Zend_Controller_Action)
					
                 
						Zend_Controller_Request_Abstract用于处理用户请求,提供各种类方法来设置和获得Controller和action的名称及各种请求的参数。另外,它可以跟踪其中的action是否已经被Zend_Controller_Dispatcher分配。本抽象类的子类可用于封装整个请求环境,允许router从中获取用户请求相关信息,或设置controller和action的名称。
					
                        
						Zend Framework默认使用Zend_Controller_Request_Http类来处理用户请求,该类可用于访问HTTP请求相关信息(用户请求不一定通过HTTP,那么就需要你自己实现相关的类--Haohappy注),
                    
                        Zend_Controller_Router_Interface用于定义router。路由是将检查用户请求并决定由哪一个controller,和其中哪一个 Action来接受请求的过程。request对象中的Controller,action和可选的参数将被Zend_Controller_Dispatcher处理。路由只发生一次:当请求被服务器接收到时,在分配到第一个控制器之前。
						
						(所谓router,和我们熟知的网络路由器的功能是很相似的,具有判断网络地址和选择路径的功能,这里就是用来定位到某个控制器中的某个方法 --Haohappy注) 
                    
                      
						默认的router是Zend_Controller_Router,它将一个Zend_Controller_Request_Http指定的URI分解成controller,action和参数。例如:URLhttp://localhost/foo/bar/key/value将被分解成foo controller,
                        bar action,并带有参数key,参数值为value.
					
                   
				Zend_Controller_Dispatcher_Interface接口用于定义dispatcher(分配器,或称调度器、派遣器等)。
				“分配”是指从request对象中获取controller和action的名称,并映射到controller文件/类及其中action类方法的过程。如果controller或action不存在,会将请求分配到默认的控制器和方法进行处理。
                    
实际上分配过程包括初始化controller类和调用类方法。和路由不一样,路由只发生一次,而分配是一个循环发生的过程。如果request对象的分配状态被重设为false,则循环就会重复,调用request中设置的方法。如果request对象的分配状态被设置成true,则分配过程结束。
                       
					默认的dispatcher是Zend_Controller_Dispatcher。它规定了控制器类命名首字母大写,并以Controller结尾,而action方法则是首字母小写,以Action结尾,例如:
					SomeFooController::barAction. 
					在例子中,控制器是somefoo,而action是bar.
					
                      
					另外,在加载一个控制器的时候,你可以指定一个module(模块)。有了module,我们可以将controller放在一个子目录中,而不用全部放在controllers目录下。要使用module,可以在front controller中设置参数 useModules:
                    
						$front->setParam('useModules', true);
						
					
举个例子,看下面的URL:
http://example.com/user/news/action
                    
					在上面的例子中,我们指定了'user'模块,并调用其中的news控制器。dispatcher会将其解释成User_NewsController类,并在User/NewsController.php文件中寻找该类。
                    
Module非常有用,当你想把代码分散到子目录中去的时候,或者使用第三方代码时,或者在不同的应用中重用相同的控制器时。
					Zend_Controller_Action是最基本的控制器。每个具体的控制器都是从Zend_Controller_Action类继承而来,是Zend_Controller_Action的子类,并且有自己的action方法。
					
                     
					Zend_Controller_Response_Abstract定义了基础的响应类,用于收集并返回action的响应,包括响应的头部(header)和主体(body),由于它使用了 __toString()方法,所以可以直接用echo来一次性输出所有header和内容。
                    
                       
						默认的响应类是Zend_Controller_Response_Http,它很适合于HTTP环境下使用。
                    
		
			Zend_Controller的工作流程相当简单。Zend_Controller_Front接收一个请求,然后由Zend_Controller_Router来决定分配给哪个controller。Zend_Controller_Router把URI分解,便于设定请求中的controller和action的名称。Zend_Controller_Front接着进入一个分配循环,调用Zend_Controller_Dispatcher,把dispatcher传给request,来调用请求中指定的具体的(或默认的)controller和action进行处理。在controller结束后,又把控制权交加给 Zend_Controller_Front。如果controller发现需要调用另一个controller(request的分配状态被清零),循环会一直继续直到另一次分配执行完毕。
		
           
			Request对象是一个简单的“值对象”(value object),在 Zend_Controller_Front和router、dispatcher和controller间传递。它封装了controller、action名称及要传递给某个action的参数,还有请求环境中的其它信息,请求环境可以是HTTP、命令行或PHP-GTK等。
		
                
				controller的名称可以通过getControllerName() 和setControllerName()来访问和设置。
			
                
				action的名称可以通过getActionName() 和setActionName()来访问和设置。
			
             
			传递给action的参数是一个关联数组,可以通过getParams()和 setParams()访问和设置,或者只访问和设置其中一个参数,可以用getParam() 和 setParam()。
			
           根据请求的不同类型,不同的请求类中可能有各种可用的方法,例如默认的请求类是Zend_Controller_Request_Http,它有一些用于获取请求URI、路径信息,$_GET和$_POST参数等的类方法。
        
request对象被传递给front controller,或者如果没有提供request对象,会自动在分配过程一开始时实例化生成,在路由发生之前。request对象会被传递给dispatch循环中的每个对象。
另外,request对象在测试时非常有用。程序员可能会构造请求环境,包括controller、action、参数、URI等,并传递请求对象到front controller,来测试整个程序的工作流。同时使用request和response对象,精细和准确的单元测试将变成可能。
在你构建第一个控制器之前,你需要理解Zend_Controller_Router中的重定向过程是如何工作的。记住工作流程分为两步:一是路由(routing),只发生一次;二是分配(dispatching),循环过程。
         Zend_Controller_Front 调用Zend_Controller_Router(或者你自己注册的router)来使一个URI映射到一个controller及其中的action上。Zend_Controller_Router从request对象中获取URI,并分解之,决定将调用的controller、action和其它URL参数,并把分解所得的这些结果存入request对象。
		
router使用很简单的方法来决定使用的controller及其action:
http://framework.zend.com/controller/action/
上面controller就是我们要采用的控制器,action就是我们要采用的action。
可选择地,参数可以在URI中定义,并传递给controller。格式为key/value :
http://framework.zend.com/controller/action/key1/value1/
	
			如果URL中controller或action/这部份没有写,Zend_Controller_Dispatcher会尝试从request对象的参数中获取相应的值,如果没有找到,则使用默认值。不论controller还是action,默认都是调用index。如:
				
http://framework.zend.com/roadmap/future/ Controller: roadmap Action : future http://framework.zend.com/roadmap/ Controller: roadmap Action : index http://framework.zend.com/ Controller: index Action : index
你也可以通过几种方式把controller放在子目录或模块下:
                    
				使用下划线_来命名控制器,例如:http://framework.zend.com/admin_roadmap/future 将映射到Admin_RoadmapController控制器。如果你不想使用下划线,也可以使用其它分隔符号,通过dispatcher的setPathSeparator()方法可以设置。
                
                   
				通过设置front controller的useModules参数,你可以使用干净漂亮的URI来访问子目录下的控制器。上例将访问http://framework.zend.com/admin/roadmap/future。要达到这个目的,可以在front controller或者router中设置useModules参数:
                
				$front->setParam('useModules', true);
				// or
				$router->setParam('useModules', true);
				
这样的设置对于基本的router和RewriteRouter都有效。
![]()  | 
Flexibility 灵活性 | 
|---|---|
如果你想得到更多灵活性,你可以看看这里: 第 7.4.3 节 “Zend_Controller_Router_Rewrite”。  | 
           
		controller和其中的action名称,及任何参数都在request对象中设置。当Zend_Controller_Front进行dispatch循环时,request对象将被传递给 Zend_Controller_Dispatcher。
		
         
			“分配”(Dispatching,是指分发请求到具体的控制器的过程,也是调用控制器和方法的过程,从这个角度说理解为“调度”更为准确 --Haohappy注)是根据request对象(Zend_Controller_Request_Abstract),从中得到controller和action名称及参数,然后实例化一个controller并调用其中方法的过程。如果没有发现controller和action的名称,它会使用默认值。 Zend_Controller_Dispatcher指定index作为默认值,但允许开发者自行指定默认值,可以通过setDefaultController()和setDefaultAction()方法。
		
调度过程发生于front controller内部的一个循环中。在调度发生之前,前端控制器把请求分解,得到控制器、方法的名称及参数,然后进行一个调度循环,分派请求。
在每次迭代的开始,request对象中都会有个标识变量(flag)来指示当前action是否已经被分配。如果一个action或者pre/postDispatch(分配前/后)插件清空了该标识变量,则分配过程会继续下去,尝试再次分配该请求。通过改变请求中的controller和/或action,或重设flag,程序员可以定义一定的“请求链”并执行。
            The action controller method that controlls such dispatching is
            _forward(); call this method from any of the
            pre/postDispatch() or action methods, providing a controller,
            action, and optionally any additional parameters you may wish to
            send to the new action:
		控制分配过程的类方法是 _forward(),在任何 pre/postDispatch()方法或者action方法中调用该方法,即可调用另一个action:
        
			public function myAction()
			{
			  // 进行一些处理...    
			  //跳转到另一个action,FooController::barAction():
			  $this->_forward('foo', 'bar', array('baz' => 'bogus'));
			}
			
         response对象与request对象从逻辑上说是相对应的,它的目的是收集服务器返回的内容的header和body。另外,front controller将把捕捉到的异常传递到response对象中,允许程序员优雅地处理异常。这个功能可以通过设设置 Zend_Controller_Front::throwExceptions(true)来实现:
        
$front->throwExceptions(true);
           
			由于response对象使用了__toString()方法,所以你可以很安全地用echo来输出该对象。也就是这样使用:
        
echo $controller->getResponse(); // or $response = $controller->getResponse(); echo $response;
程序员应当在controller中使用response对的是,不要直接输出内容或头部,应该把这些输出放到response对象中去:
// Within an action controller action:
// Set a header
$this->getResponse()
    ->setHeader('Content-Type', 'text/html')
    ->appendBody($content);
这样做,所有的header会在发送内容之前设置一次。
           程序中是否发生异常,可以使用isException()来检查response对象的flag,并且通过getException()来得到该异常。另外,你也可以定制自己的response对象,使程序出错时转向到出错信息页、记录异常信息或格式化异常信息等。
        
在front controller进行dispatch()之后,你可以得到response对象,或者请求front controller返回response对象而不是直接显示输出。
// retrieve post-dispatch:
//得到dispatch后的响应:
$front->dispatch();
$response = $front->getResponse();
if ($response->isException()) {
    // log, mail, etc...
}
// Or, have the front controller dispatch() process return it
// 或者,让front controller在dispatch()执行过程中返回响应
$front->returnResponse(true);
$response = $front->dispatch();
// do some processing...
// finally, echo the response
//最后,用echo输出响应信息
echo $response;
        默认地,异常信息不会被显示。要显示异常信息,需要通过调用renderExceptions(),或者启用front controller的throwExceptions()方法,例如:
        
$response->renderExceptions(true); $front->dispatch($request, $response); // 或者 $front->returnResponse(true); $response = $front->dispatch(); $response->renderExceptions(); echo $response; // 或者 $front->throwExceptions(true); $front->dispatch();