1 <? php 2 class IndexController extends Zend_Controller_Action 3 { 4 public function contactAction() 5 { 6 // $this->render("index"); 7 //$this->render(); 8 //$this->renderScript("sidebar.phtml"); 9 10 11 //$this->_helper->viewRenderer("sidebar"); 12 13 //$this->view->render("sidebar.phtml"); 14 //$this->view("sidebar"); 15 16 } 17 } 18 ?>
总结下来,似乎就是这三中render了(欢迎补充) 1.自身render 先看第一种 // $this->render("index"); //$this->render(); //$this->renderScript("sidebar.phtml"); 这是直接使用Zend_Controller_Action类的render方法 第一句是render了另一个action所对应的视图(看清了 是render那个action对应的视图 而不是执行那个action!) 第二句式render本action对应的视图,这个有什么意义呢(因为很多情形你看不到这个写法的),这个下面再说. 第三句是render特定的视图文件,这里你可能认为前两个方法实际是调用了这个renderScript,其实不是如此. 下面就阐述一下.顺便解释第二句的原因. Zend_Controller_Action类的render方法中其实是有两个分支的 如下render函数代码 1 public function render( $action = null , $name = null , $noController = false ) 2 { 3 if ( ! $this -> getInvokeArg( ' noViewRenderer ' ) && $this -> _helper -> hasHelper( ' viewRenderer ' )) { 4 return $this -> _helper -> viewRenderer -> render( $action , $name , $noController ); 5 } 6 7 $view = $this -> initView(); 8 $script = $this -> getViewScript( $action , $noController ); 9 10 $this -> getResponse() -> appendBody( 11 $view -> render( $script ) , 12 $name 13 ); 14 }
可以看到一种情形是利用(代理)了视图助手类(viewRenderer)的render方法 另一种是禁用助手时的情形 就得亲自上阵了,这也就是render()出现的原因,你禁用了视图助手后要输出本action对应视图内容可以使用render()来完成 2.通过视图助手viewRenderer 上面说起了视图助手,那我们来看action中的第二个片段,正是借助视图助手来进行 //$this->_helper->viewRenderer("sidebar"); 实际上这里这句话并不是render内容,而是指定了要render哪个视图,参考Zend_Controller_Action_Helper_ViewRenderer类的这个函数 1 public function direct( $action = null , $name = null , $noController = null ) 2 { 3 $this -> setRender( $action , $name , $noController ); 4 }
那么输出呢 是怎么输出的? 可以在 $this->_helper->viewRenderer("sidebar"); 后直接调用$this->render();即可. 但是实际上你完全不用调用,只写那一句就行. 你不写render的时候,视图助手会来替你完成.在Zend_Controller_Action类中的dispatch方法中有这么一句 $this->_helper->notifyPostDispatch(); _helper是什么? 是一个Zend_Controller_Action_HelperBroker类 ,其中有这个方法 1 public function notifyPostDispatch() 2 { 3 foreach (self :: getStack() as $helper ) { 4 $helper -> postDispatch(); 5 } 6 }
可以看到调用了其中各个助手的 postDispatch (); 而 viewRenderer 正是其中的一个助手,其 postDispatch 方法如下 1 public function postDispatch() 2 { 3 if ( $this -> _shouldRender()) { 4 $this -> render(); 5 } 6 }
正是在这里视图助手帮你进行了render,如果你自己render了,聪明的视图助手会知晓的,可以查看下在_shouldRender()中的这个 $this->getRequest()->isDispatched(),及Zend_Controller_Front 类中dispatch方法的这句话:$this->_request->setDispatched(true); 3.终极render 关于Zend_View->render() 好了现在我们来看看Zend_View的render(). 在上面的两个中我们都说到了render(),比如action的render和视图助手的render 那么你该问个问题:就这样了?后面呢? 后面的才是关键的. 在action的render中,你可能注意到这句话了 10 $this -> getResponse() -> appendBody( 11 $view -> render( $script ) , 12 $name 13 ); 而我们再看看viewRenderer的render(),viewRenderer的render方法其实是调用了 renderScript 方法,代码如下 1 public function renderScript( $script , $name = null ) 2 { 3 if ( null === $name ) { 4 $name = $this -> getResponseSegment(); 5 } 6 7 $this -> getResponse() -> appendBody( 8 $this -> view -> render( $script ) , 9 $name 10 ); 11 12 $this -> setNoRender(); 13 }
可以看到这里跟action的render有点类似,也有同样的那句话. 就是说action的render和viewRenderer的render其实都是调用Zend_View的render,拿到内容而后置放到response中 Zend_View的render: 1 public function render( $name ) 2 { 3 // find the script file name using the parent private method 4 $this -> _file = $this -> _script( $name ); 5 unset ( $name ); // remove $name from local scope 6 7 ob_start (); 8 $this -> _run( $this -> _file); 9 10 return $this -> _filter( ob_get_clean ()); // filter output 11 }
至于run: 1 protected function _run() 2 { 3 if ( $this -> _useViewStream && $this -> useStreamWrapper()) { 4 include ' zend.view:// ' . func_get_arg ( 0 ); 5 } else { 6 include func_get_arg ( 0 ); 7 } 8 }
那么你就明白了最开始代码中的第13行 13 //$this->view->render("sidebar.phtml"); 其实是个幌子,哈.这句话只是得到了内容,但是呢 没做处理! 所以我们应该这样 13 echo $this->view->render("sidebar.phtml"); 再然后呢?参看Zend_Controller_Front类dispatch $this->_response->sendResponse(); 及Zend_Controller_Response_Abstract类 1 public function outputBody() 2 { 3 foreach ( $this -> _body as $content ) { 4 echo $content ; 5 } 6 }
而至于第14行 14 //$this->view("sidebar"); 貌似合理,瞪一眼就知道了:这句话地地道道的错误 action 中没有这个方法,__call中也没有相应处理,不象 _helper->viewRenderer("sidebar"); 在 _helper针对该情况在__call中有相应处理 1 public function __call( $method , $args ) 2 { 3 $helper = $this -> getHelper( $method ); 4 if ( ! method_exists ( $helper , ' direct ' )) { 5 require_once ' Zend/Controller/Action/Exception.php ' ; 6 throw new Zend_Controller_Action_Exception( ' Helper " ' . $method . ' " does not support overloading via direct() ' ); 7 } 8 return call_user_func_array ( array ( $helper , ' direct ' ) , $args ); 9 }
没有viewRenderer这个方法,于是去寻找名为viewRenderer并且有direct方法的助手,找到了即执行这个direct方法(上面第二部分贴过代码了) 至于viewRenderer这个助手存放时,要注意到他的名字是死的 就是"viewRenderer",具体看Zend_Controller_Action_Helper_Abstract类的getName方法 1 public function getName() 2 { 3 $full_class_name = get_class ( $this ); 4 5 if ( strpos ( $full_class_name , ' _ ' ) !== false ) { 6 $helper_name = strrchr ( $full_class_name , ' _ ' ); 7 return ltrim ( $helper_name , ' _ ' ); 8 } else { 9 return $full_class_name ; 10 } 11 }
之所以提到这点是因为在Zend_Controller_Action_Helper_ViewRenderer注释中你能看到这句话 // In your action controller methods: $viewHelper = $this->_helper->getHelper('view'); 而实际上你复制这句话到your action controller methods中去 只会出错 Exception information:
Message: Action Helper by name View not found
个人感觉php Zend Framework还是很不错,虽然一直没搞好调试器 但是非常满意于可以随处置放var_dump