視圖層又叫表現層,也有人叫UI,幾年前當MVC開發模式在Web開發中並不是很流行時,人們最常討論的是“代碼邏輯與Html介面的分離”,PHP中最有代表可能是Smarty模板技術吧,因為當時的Web開發並不需要現在那麼複雜,隨著越來越多“軟體Web化”,代碼邏輯越來越複雜,MVC模式也就越來越被人重視了。
在我們這個架構中視圖採用的是PHP解析引擎,因為其實現簡單,效率較高,且較通用,你可以在裡邊寫任意可執行檔PHP代碼,就像沒有用架構一樣。當然,你若喜歡Smarty那種模板風格的“標籤”式視圖,也可以替換掉相應的代碼,自己實現之(對模板的解析就是個尋找替換的過程而已)。
上一節中我們建立了HomeController控制器,並添加了index動作,現在讓我們先為它建立對應的視圖:
上一節中我們已經能夠通過 http://www.example.com/home/index 來執行HomeController中的indexAction方法了,如果讓程式執行完這個方法後轉向視圖的執行呢?如何把在動作中向視圖傳遞值呢?為了達到我們的目的,下面需要建立一個LQP_Controller架構類:
- 在library/LQP下建立檔案Controller.php,內容如下:
<?php/** * 控制器的基類 * * @author z */class LQP_Controller { private $_controllerName, $_viewName; public function lqp_init($controllerName,$viewName) { $this->_controllerName = $controllerName; $this->_viewName = $viewName; $this->init(); } function init() { //由子類去實現 } function loadView($viewData) { if(empty($this->_viewName)) return ; require_once APP_VIEW_DIR."/{$this->_controllerName}/{$this->_viewName}.php"; }}?>
這個LQP_Controller 類是每個控制器的父類,其中會提供一些常用的方法,目前有三個主要方法,lqp_init、init、loadView,其中init為一個“事件方法”,當程式開始執行時總會先執行init中的代碼,子類可以覆蓋這個方法以添加一些需要“事先執行”的代碼;lqp_init是架構控制器的初始化方法,loadView用於載入視圖,你不應該覆蓋這些方法,也不應在你的代碼中調用這些方法,此方法會有架構在Rewrite時自動調用,架構調用原理如下:
a) 修改Loader.php檔案,加入一句:require_once 'Controller.php';
b) 修改HomeController.php檔案,讓類HomeController繼承自LQP_Controller,如下:
<?phpclass HomeController extends LQP_Controller{ function indexAction() { }};?>
c) 修改Rewrite.php檔案,添加一個disponseView方法用來作為解析視圖的入口函數:
private function disponseView(LQP_Controller $controller, $actionReturnData) { if(is_bool($actionReturnData)) $controller->setView($controller->getViewName().($actionReturnData?'Success':'Fail')); $controller->loadView($actionReturnData); }
然後修改disponse方法為如下形式:
function dispatch() { $controllerClassName = ucfirst($this->_controllerName)."Controller"; $controllerFile = APP_CONTROLLER_DIR."/$controllerClassName.php"; require_once $controllerFile; $controller = new $controllerClassName(); $controller->lqp_init($this->_controllerName,$this->_actionName); $action = $this->_actionName; $action .= "Action"; $actionReturnData = $controller->$action(); $this->disponseView($controller, $actionReturnData); }
其中修改的代碼已標出,關於$actionReturnData後面會再詳解。
這樣修改之後當我們訪問http://www.example.com/home/index 時將會看到“這是home/index視圖”的資訊,下面說一下控制器與視力間是如何傳值的。
如果你用過PHP架構,應該會知道,當在動作中寫下如:$this->varName = “abc”; 的代碼時,在視圖就可以使用$this->varName或$varName之類的變數取到設定的值,這是如何?的呢?如果你對PHP的require / include機制比較瞭解,在查看了上面的代碼後應該不難理解了:我們使用LQP_Controller中的loadView方法載入視圖,而每個控制器都繼承自LQP_Controller,自然控制器類的中定義的“屬性”就可以被訪問到了。而不加$this的形式一般都是對控制器對象使用了php的extract函數。個人認為那樣沒什麼必要,故本架構中將採用$this->varName的形式,當然也有例外,比如“傳回值”,後面會講到。
下面可以做個傳值的實驗:
- 在HomeController中的indexAction方法裡寫上一行代碼:
$this->hello = “hello world”;
- 在views/home/index.php的body中加入一行:
<?php echo $this->hello ?>
- 訪問http://www.example.com/home/index看看是不是會輸出“hello world”呢?
總節一下,與上一節類似本節也只是簡單講解了視圖的實現原理,後面的章節中會逐漸加入一些“新鮮元素”,只能加入這些元素,使用架構開發才真正的帶給你好處。
下一節會講講架構中的HttpRequest與HttpResponse,做過.net/java開發的對這兩個類一定不會陌生,呵呵
本節代碼下載:http://cid-8248e4adbf2b92f3.office.live.com/self.aspx/.Public/Lesson%205.rar