http://www.pkphp.com/2010/01/09/zend-framework-render-intro/
通常在我們利用ZF實現php的mvc時,最關鍵的地方當然是Controller類的各種action方法,在action方法中,我們確定及輸出內容. 在類 abstract class Zend_Controller_Action 中的dispatch方法你可以發現這一行 $this->$action();
那麼如何確定及輸出內容呢,就是進行render了,不過這個render卻是有好幾個的,下面列出這幾個情形
<?php
class IndexController extends Zend_Controller_Action
{
public function contactAction()
{
//$this->render(“index”);
//$this->render();
//$this->renderScript(“sidebar.phtml”);
//$this->_helper->viewRenderer(“sidebar”);
//$this->view->render(“sidebar.phtml”);
//$this->view(“sidebar”);
}
}
?>
總結下來,似乎就是這三中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函數代碼
public function render($action = null, $name = null, $noController = false)
{
if (!$this->getInvokeArg(‘noViewRenderer‘) && $this->_helper->hasHelper(‘viewRenderer‘)) {
return $this->_helper->viewRenderer->render($action, $name, $noController);
}
$view = $this->initView();
$script = $this->getViewScript($action, $noController);
$this->getResponse()->appendBody(
$view->render($script),
$name
);
}
可以看到一種情形是利用(代理)了視圖助手類(viewRenderer)的render方法
另一種是禁用助手時的情形 就得親自上陣了,這也就是render()出現的原因,你禁用了視圖助手後要輸出本action對應視圖內容可以使用render()來完成
2.通過視圖助手viewRenderer
上面說起了視圖助手,那我們來看action中的第二個片段,正是藉助視圖助手來進行
//$this->_helper->viewRenderer(“sidebar”);
實際上這裡這句話並不是render內容,而是指定了要render哪個視圖,參考Zend_Controller_Action_Helper_ViewRenderer類的這個函數
public function direct($action = null, $name = null, $noController = null)
{
$this->setRender($action, $name, $noController);
}
那麼輸出呢 是怎麼輸出的?
可以在$this->_helper->viewRenderer(“sidebar”); 後直接調用$this->render();即可.
但是實際上你完全不用調用,唯寫那一句就行.
你不寫render的時候,視圖助手會來替你完成.在Zend_Controller_Action類中的dispatch方法中有這麼一句
$this->_helper->notifyPostDispatch();
_helper是什麼? 是一個Zend_Controller_Action_HelperBroker類 ,其中有這個方法
public function notifyPostDispatch()
{
foreach (self::getStack() as $helper) {
$helper->postDispatch();
}
}
可以看到調用了其中各個助手的postDispatch();
而viewRenderer正是其中的一個助手,其postDispatch方法如下
public function postDispatch()
{
if ($this->_shouldRender()) {
$this->render();
}
}
正是在這裡視圖助手幫你進行了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中,你可能注意到這句話了
$this->getResponse()->appendBody(
$view->render($script),
$name
);
而我們再看看viewRenderer的render(),viewRenderer的render方法其實是調用了renderScript方法,代碼如下
public function renderScript($script, $name = null)
{
if (null === $name) {
$name = $this->getResponseSegment();
}
$this->getResponse()->appendBody(
$this->view->render($script),
$name
);
$this->setNoRender();
}
可以看到這裡跟action的render有點類似,也有同樣的那句話.
就是說action的render和viewRenderer的render其實都是調用Zend_View的render,拿到內容而後置放到response中
Zend_View的render:
public function render($name)
{
// find the script file name using the parent private method
$this->_file = $this->_script($name);
unset($name); // remove $name from local scope
ob_start();
$this->_run($this->_file);
return $this->_filter(ob_get_clean()); // filter output
}
至於run:
protected function _run()
{
if ($this->_useViewStream && $this->useStreamWrapper()) {
include ‘zend.view://‘ . func_get_arg(0);
} else {
include func_get_arg(0);
}
}
那麼你就明白了最開始代碼中的第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類
public function outputBody()
{
foreach ($this->_body as $content) {
echo $content;
}
}
而至於第14行
14 //$this->view(“sidebar”);
貌似合理,瞪一眼就知道了:這句話地地道道的錯誤
action 中沒有這個方法,__call中也沒有相應處理,不象_helper->viewRenderer(“sidebar”);在 _helper針對該情況在__call中有相應處理
public function __call($method, $args)
{
$helper = $this->getHelper($method);
if (!method_exists($helper, ‘direct‘)) {
require_once ‘Zend/Controller/Action/Exception.php‘;
throw new Zend_Controller_Action_Exception(‘Helper ”‘ . $method .‘“ does not support overloading via direct()‘);
}
return call_user_func_array(array($helper, ‘direct‘), $args);
}
沒有viewRenderer這個方法,於是去尋找名為viewRenderer並且有direct方法的助手,找到了即執行這個direct方法(上面第二部分貼過代碼了)
至於viewRenderer這個助手存放時,要注意到他的名字是死的 就是”viewRenderer”,具體看Zend_Controller_Action_Helper_Abstract類的getName方法
public function getName()
{
$full_class_name = get_class($this);
if (strpos($full_class_name, ‘_‘) !== false) {
$helper_name = strrchr($full_class_name, ‘_‘);
return ltrim($helper_name, ‘_‘);
} else {
return $full_class_name;
}
}
之所以提到這點是因為在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