sunyke 发表于 2015-8-24 08:32:17

PHP框架开发:五、视图(View)的实现

  视图层又叫表现层,也有人叫UI,几年前当MVC开发模式在Web开发中并不是很流行时,人们最常讨论的是“代码逻辑与Html界面的分离”,PHP中最有代表可能是Smarty模板技术吧,因为当时的Web开发并不需要现在那么复杂,随着越来越多“软件Web化”,代码逻辑越来越复杂,MVC模式也就越来越被人重视了。
  在我们这个框架中视图采用的是PHP解析引擎,因为其实现简单,效率较高,且较通用,你可以在里边写任意可执行的PHP代码,就像没有用框架一样。当然,你若喜欢Smarty那种模板风格的“标签”式视图,也可以替换掉相应的代码,自己实现之(对模板的解析就是个查找替换的过程而已)。
  上一节中我们创建了HomeController控制器,并添加了index动作,现在让我们先为它建立对应的视图:


[*]在views下创建home文件夹,在home下创建index.php文件 (注意大小写)
index.php是一个标准的Html文件,内容如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>页面标题</title>
</head>
<body>
这是home/index视图      
</body>
</html>

  
  上一节中我们已经能够通过 http://www.example.com/home/index 来执行HomeController中的indexAction方法了,如果让程序执行完这个方法后转向视图的执行呢?如何把在动作中向视图传递值呢?为了达到我们的目的,下面需要创建一个LQP_Controller框架类:


[*]在library/LQP下创建文件Controller.php,内容如下:


<?php
/**
* 控制器的基类
*
* @author z
*/
classLQP_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,如下:


<?php
class 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
页: [1]
查看完整版本: PHP框架开发:五、视图(View)的实现