MVC处理过程如图1-3所示,首先控制器接收用户的请求,并决定应该调用哪个模型来处理;然后模型根据用户请求进行相应的业务逻辑处理,并返回数据;最后控制器调用相应的视图来格式化模型返回的数据,并通过视图呈现给用户。
图 1‑3 MVC设计模式
2. MVC模式的优点
使用PHP开发出来的Web应用,初始的开发模板就是混合的数据编程。例如,直接向数据库发送请求并用HTML显示,开发速度往往比较快,但由于数据页面的分离不是很直接,因此很难体现出业务模型的样子或者模型的重用性。产品设计弹性力度很小,很难满足用户的多样化的需求。MVC要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好的体现。
首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按 照MVC 设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。
控制器还有一个好处,就是可以用它来连接不同的模型和视图去完成用户的需求,这样它可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择模型进行处理,然后通过视图将处理结果显示给用户。
最后,MVC还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。
综上所述,MVC是构筑软件非常好的框架模式,将业务处理与显示分离,强制地将应用分为模型、视图及控制层。总之,MVC模式会使得应用更加强壮,更加有弹性,更加个性化。
3. MVC框架模式的实现
在实现MVC框架模式之前,我们先来回顾一下不使用MVC的开发流程。这里有一个网站的三个页面,分别是首页(index.html),列表页(arc_list.html)和内容页(article.html)。这三个页面都是静态页面。接下来实现静态页面改写成PHP动态页面,以便能及时从数据库中读取最新内容。这里只实现首页中的“行业百科”模块,效果如图1-4所示。
图1-4 首页中“行业百科”模块效果图
静态页面index.html中“行业百科”模块代码如下。
使用PHP语言从数据库中读取“行业百科”栏目下的文章标题,重新编写成index.php文件,代码如下所示。
exec("set names 'utf8'");
$query = "SELECT title FROM ds_article WHERE cid='14'";
try {
//执行SELECT查询,并返回PDOstatement对象
$pdostatement = $dbh->query($query);
$result=$pdostatement->fetchAll();
foreach ($result as $row)
{
?>
- href="#"
target=_blank>
getMessage();
}
?>
实现了首页中“行业百科”从数据库查询功能后,首页中其他功能,还有列表页,内容页的实现过程也和 “行业百科”类似,这里就不列举了。
如此编写代码是很多初学者经历的一个阶段,就是将PHP代码和HTML、CSS、JavaScript代码混合在一起使用,如果有人之前这样去做的话,能否体会出代码混合在一起编写所带来的麻烦?
首先就是不利于代码的重复使用,如刚才的“行业百科”模块。如果在列表页和内容页中也有一样的模块,则需要重复编写,或者把这部分的代码放到一个文件中,频繁使用include语句去调用。或者代码连重复利用都不行,如数据库操作等。其次就是不利于较大项目的团队合作,如开发人员不需要使用HTML、CSS和JavaScript等技术;前台美工不需要使用数据库、PHP开发。最后,不利于代码的后期扩展。如在后期的项目维护过程中,代码混杂,层次不清,将导致重复修改。
如何解决这些不利于软件开发的缺点呢?毫无疑问,MVC框架模式就能解决,具体处理流程如下。步骤1:创建models/Article.php,并在文件中定义文章表模型类Article,其中的find()方法返回查询数据的结果。
exec("set names 'utf8'");
$query = "SELECT title FROM ds_article WHERE cid='14'";
try {
//执行SELECT查询,并返回PDOstatement对象
$pdostatement = $dbh->query($query);
return $result=$pdostatement->fetchAll();
} catch (PDOException $e) {
echo $e->getMessage();
}
}
}
?>
步骤2:在framework/framework.php文件中创建控制器的基类CController,并实现控制器渲染视图方法render(),这个方法的功能是加载指定目录下的视图文件,并将控制器中的数据传递到视图文件中。
变量值
*/
public function render($viewName, $data){
extract($data, EXTR_PREFIX_SAME,'data');//将数组$data变成变量的形式
require($viewName);//包含视图文件
}
}
?>
步骤3:创建Controllers/DefaultController.php文件,创建控制器DefaultController继承父类CController,创建首页管理方法actionIndex(),在其中创建模型Article对象,并调用find()方法获取数据,渲染视图,并把数据输出到视图页面。
find();
//渲染视图,并把数据输出到视图页面
$this->render("../views/index.php",array("result"=>$result));
}
//列表页管理
public function actionList(){}
//内容页管理
public function actionArticle(){}
}
$default_con = new DefaultController();
$default_con->actionIndex();
?>
步骤4:创建views/index.php,在视图文件中,对查询结果变量$resule进行循环处理,生成完整的HTML页面。
实现的
MVC
框架执行流程如图
1-5
所示。
1. 用户直接调用控制器实例对象。控制器调用类中的 action方法(动作)。
2. 控制器调用模型实例对象从数据库中读取数据。
3. 渲染视图。
4. 视图读取并显示模型的属性。
5. 动作完成视图渲染并将其返回给用户。
本节中按照MVC框架模式的工作思想,完成了控制器、模型、视图三部分的代码分离。我们访问程序,需要去访问controllers目录下的控制器文件,这样做存在明显的设计缺陷,如果控制器文件较多,则会导致系统结构访问混乱,后期维护困难、安全性差等一系列问题,而且不便于系统的统一管理。
下一节中将新增入口文件,通过解析用户请求的URL,提取出控制器名和动作方法名,创建相应控制器实例对象,并执行动作方法。