通常在我們利用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 Zend Framework還是很不錯,雖然一直沒搞好調試器
但是非常滿意于可以隨處置放var_dump