明晰php Zend Framework中的render

搞asp.net mvc時對php mvc發生興趣 看了看Zend Framework(下簡稱ZF) 
能夠對比理解mvc
對一個比較核心的函數render非常迷惑了一陣 記錄下明晰過程

一般在咱們利用ZF實現php的mvc時,最關鍵的地方固然是Controller類的各類action方法,在action方法中,咱們肯定及輸出內容. 在類 abstract class Zend_Controller_Action 中的dispatch方法你能夠發現這一行 $this->$action();

那麼如何肯定及輸出內容呢,就是進行render了,不過這個render倒是有好幾個的,下面列出這幾個情形
複製代碼
 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

我的感受php Zend Framework仍是很不錯,雖然一直沒搞好調試器
可是很是滿意於能夠隨處置放var_dump
相關文章
相關標籤/搜索