热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PHP中MVC架构机制详解

MVC是MODEL_VIEW_CONTROL的缩写。MODEL_VIEW_CONTROL是软件设计的典型结构。在这种设计结构下,一个应用被分为三个部分
1.MVC概述
  1.1 什么是MVC

  MVC是MODEL_VIEW_CONTROL的缩写。MODEL_VIEW_CONTROL是软件设计的典型结构。在这种设计结构下,一个应用被分为三个部分:model,view和controller,每个部分负责不同的功能。model是指应用程序的数据,以及对这些数据的操作;view是指用户界面;controller负责用户界面和程序数据之间的同步,也就是完成两个方向的动作:一、在根据用户界面(view)的操作完成对程序数据(model)的更新,二、将程序数据(model)的改变及时反应到用户界面(view)上。 

  1.2 MVC的优点

  使程序结构更加清晰,增强代码稳定性。
  在MVC机制下,应用被清晰的分为model,view,controller三个部分,这三个部分分别依次对应了业务逻辑和数据、用户界面、用户请求处理和数据同步。我们知道,对于业务逻辑和数据、用户界面、用户请求处理和数据同步这三部分功能来讲,用户界面发生变动的可能性最大,控制部分变动次之,而业务逻辑是最稳定的。所以这种模块功能的划分有利于在代码修改过程中选取重点,而不是把具有不同功能的代码混杂在一起造成混乱。 

  便于开发小组进行分工
  将应用划分为model,view,controller三个部分,还有利于在项目小组内按照小组成员各自的擅长进行分工,有利于三个部分并行开发、加快项目进度。

2.MVC机制的实现

  2.1概述

  2.1.1应用的技术 
  MVC在某个特定应用上的实现是与该应用的具体技术密切相关的。在网站开发方面,JAVA是比较成熟和典型的,以一个EJB的项目为例,大部分的系统可能采用HTML技术,和J2EE(Java2,Enterprise Edition)的相关技术,包括:HTML,JSP,JavaBean,EnterpriseJavaBean,Servlet。这些技术分布于model,view,controller三个模块之中:view部分用到HTML、JSP和JavaBean技术;controller部分用到Servlet、StatelessSession Bean 、JavaBean 技术;model部分可能用到EntityBean、Stateless Session Bean、JavaBean技术。 

  但是,我们在这个项目用的是PHP技术来实现,因此,我们需要作出一些折衷。一方面,要尽量使程序的逻辑实现能够平滑地迁移到另一种技术实现(如J2EE),但同时,我们也要考虑到PHP这种脚本语言的局限性。PHP在对于面向对象的支持上同JAVA这种OO的语言不是同一档次,甚至比PERL都要差得很多。不过,幸运的是,我们的运气还不算太坏,因为PHP里面的PEAR是一个面向对象的扩展。使用PEAR的规范,我们一方面可以使用现有的一些PEAR模块,另一方面,可以使我们的程序是能够按照OO的思想来实现业务逻辑的。因此,我们将废弃过去那种模块化,过程化的编程方式,转变思路,将所有的东西都用类包装起来。

在开始介绍实际的设计之前,我们不妨看看这个项目的需求情况

  2.1.2项目需求 
  这个项目目的很简单,就是要做一个网站的发布系统。发布系统应该能够支持频道,子频道,栏目的划分,特权区的划分,用户角色划分,频道各种模板的定制,文章发布的流程控制…… 

  2.1.3层次划分 
  我们的应用不但可以按MVC机制分为model,view,controller三个层次,同时还应该可以按照实现的技术和逻辑关系划分为页面表现模块,业务控制模块,事务管理模块,工具模块4个模块;也可以按照具体的业务划分模块。下面再介绍一下这两种划分方式: 

  按业务模块划分 
  按实际业务分为用户管理、文章发布、模板维护、前台显示,系统管理五个部分。每一个部分都对应着发布系统的一个方面。这样,model、view、controller的实现组件就分布于五个业务模块之中。 

  按实现技术划分 
  由于我们的实现技术采用了HTML技术和PHP的相关技术,按照这些技术,我们又把整个应用分为页面表现层,业务控制层,事务管理层,工具模块。这样MVC的3层结构又细化为上面这4个逻辑层。

  2.2页面表现层

  这部分的实现是最为简单的。由模板和使模板实例化的render类来完成。 
  模板是使用纯HTML来编写,不存在任何的PHP代码和控制逻辑,确切地说,本层不涉及任何商业逻辑,它的用途就是根据选择的模板,和提供的实例的数据,生成一个完整的HTML页面。

  2.2.1模板机制 
  我们使用PEAR中的IT和ITX模块作为我们的模板引擎,之所以使用它,是因为ITX类是纯PEAR类,在功能上和PHPLIB中的TEMPLATE类似,但是使用上要简单一些。而且ITX有些特性特别适合这种模板的定制,考虑到我们的页面表现没有太特殊的地方,使用ITX能够满足我们的需求。 

关于ITX的具体使用细节,可以参考ITX的源代码,这里是它的一个简单的使用方法说明:

new IntegratedTemplateExtention($root = "")
构建函数,$root是装载模板文件的目录。注意,这里可能有个BUG,在使用下面的函数装载模板文件的时候,如果装载的文件名中带有路径的话,总是无法找到那个文件,所以我建议你设置$root为模板的目录,然后再使用下面的函数装载模板。

loadTemplatefile($filename, $removeUnknownVariables = true,$removeEmptyBlocks = true)
从指定的文件中加载模板,$removeUnknownVariables表示是否去掉未使用的变量标识,$removeEmptyBlocks表示是否去掉没有使用的块。

setRoot($root)
设置模板的目录

setTemplate($template, $removeUnknownVariables = true,$removeEmptyBlocks = true)
从指定的字符串中加载模板。如果你打算把模板数据存放在数据库中(推荐),这个函数是很有用的。

setCurrentBlock($blockname)
设置当前要解析的块名

setVariable($variable, $value = "")
设置变量标识的值

parseCurrentBlock()
解析当前的块

touchBlock($block)
设置指定的块,使之即使没有使用,也在输出中显示

parse($block = "__global__", $flag_recursion = false)
解析指定的块

getBlocklist()
得到模板中的块的列表

blockExists($blockname)
判断模板中是否存在指定的块

  2.2.2 模板的定义

  由于使用了ITX,模板的定义方式很简单,使用来定义一个需要实例化的HTML块,使用{varname}来定义需要实例化的变量就可以了。对于循环,我们无需在页面上表现,而是放在render类里控制,我们通过选定一个HTML块,然后反复实例化这个块,就可以生成循环的HTML代码了。下面是一个例子:


 $obj->setCurrentBlock('LIST');
 for($I=0;$I<3;$I++){
   $obj->setVariable('name','panfan');
   $obj->setVariable('sex','BOY');
   $obj->setVariable('age',$I);
   $obj->parseCurrentBlock();
 }
?>

{name}{age}{sex}
这将生成如下的HTML代码:
panfan0BOY 
panfan1BOY 
panfan2BOY

  2.2.3 实例化模板 

  如在上节所看到的,我们通过给render类设置不同的template和不同的实例化数据,将生成不同的页面。那么,如何将模板和它所对应的render联系起来呢?这是个好问题。为了把复杂的问题简单化,我们没有考虑使用一个通用的能够实例化全部的模板和数据的render,因为这样会造成这个render逻辑非常负责,而是采用许多render,每个render可以实例化一个或者几个相近的模板。每一个模板都有一个它相对应的render类的id,这些定义是我们预先定义好的。我们使用了一个xml文件来定义应用中用到的全部的模板。这个xml文件名叫:template.xml,它的基本结构是这样的: 





  在这个XML文件里面,定义了我们这个项目中所用到的全部的模板,