php mvc模式

MVC设计模式

MVC模式下,客户直接发送请求到控制器,控制器根据用户的请求的资源分发到相对应的模型来处理,模型完成了业务逻辑后,把要数据发送到视图,视图显示返回给客户。这就是web 或是说B/S架构的MVC工作流程。

控制器:

用户的所有请求会发送到控制器,由控制器来按需调用模型和视图。比如用户请求index.php 控制器文件,index.php里面不会设计到任何的数据库操作,逻辑操作。它只会寻找执行用户请求的业务模型,把所有的业务逻辑操作交给模型也就是MVC中的M。把控制器独立出来,形成单入口访问模式,方便做全局管理,比如:日志记录等。

模型:

模型是业务逻辑数据的集合,比如数据库操作,复杂的逻辑运算等。按照功能项目模块来分成一个个模型,模型间的耦合性很小有利于项目以后的扩展和修改。

视图:

Web技术中的MVC 的C层。其主要是由 HTML 、XML语言组成的界面。以前的web界面是视图和模型混杂在一起使用,形成了杂乱的代码,日后代码的维护十分困难。PHP中知名的模板引擎smarty 就是为了实现模型和视图分离的一种技术。现在smarty 在PHP行业广泛使用。

MVC思想不是为了某种语言而设计的,她适用所有的面向对象的语言。比如知名的 实现MVC思想的JAVA语言的 Struts 框架。当然PHP 框架也是百花齐放如 :Zend Framework 、 Fleaphp 、Thinkphp 、Cakephp 等,都能很好的实现MVC思想而且他们大量应用了GOF 设计模式,开发人员如果基于以上几种MVC框架进行项目开发,开发的效率和代码质量会大幅度提升。特别是多人协作开发的项目。那PHP怎么实现MVC的呢?下面教大家开发一个简单的MVC基础框架,完整代码在光盘09/20目录里。

类驱动

在php5中可以使用__autoload 函数来实现类自动加载。但单纯这样的方式不够灵活。比如类文件存放在不同的目录里面而又需要自动加载的情况里,我们就需要在__autoload函数里实现复杂的逻辑判断实现自动加载。

比如需要实例化两个类:Myblog 、Mybook。Mylog类在根目录下的Lib/test.php 文件里,Mybook类在根目录下的App/command.php 文件里。__autoload函数里实现加载:

<?php

function __autoload($class){

if($class == ‘Myblog’) include ‘Lib/test.php’;

if($class == ‘Mybook’) include ‘App/command.php’;

if(!include_once($classpath)){ //加栽类

throw new Exception(”加载类库失败“);

}

}

?>

这只是实例化两个不同目录下的两个类而已。如果项目中使用面向对象开发的话,类不会那么少,可以想下。如果要加载数个不同目录下的类,__autoload函数里实现会是多麻烦和不灵活。

在这里给出个比较简单的解决方案,而且这个解决方案在很多MVC框架中得以很好的应用

我们只需要在类的命名方式上做些改变,以类的目录路径为类名:

/Yhmphp/ App.php 里的Mysession类,命名为:Yhmphp_App_Mysession。用’_’下划线来替换

路径分割符,以相对路径下的目录路径做类名。

又比如根目录下的Lib目录下test.php 文件里面(/Lib/test.php) 有个Myblog 类,可以这样给Myblog类命名:

<?php

class Lib_Myblog{}

?>

实例化Lib_Myblog类:

<?php

$myblog = new Lib_Myblog;

?>

__autoload函数里用str_replace函数把路径分割符替换类名中的’_’下划线,这样就可以准确的找到Lib_Myblog类的所在文件的路径然后准确的加载了:

<?php

function __autoload($class){

$classpath = str_replace(’_',’/',$class).’.php’;

if(!include_once($classpath)){ //加栽类

throw new Exception(”加载类库失败“);

}

}

?>

模型的路由:

当我们给单入口文件(控制器)index.php 加上了模型选参m (index.php?m=myblog),控制器就会去寻找 myblog模型类,并实例化,然后执行myblog模型类中的 model 方法,最后执行show方法

来显示视图。

<?php

class App_Run

{

public function routing(){

$model = MOBILE_MODEL.’_’.MODEL_SWITCHING.’_’.$_REQUEST['m'];

if(class_exists($model)){

$cake = new $model;

method_exists($cake,’model’) && $cake->model(); //执行模型里面的 model方法

method_exists($cake,’show’) && $cake->show(); //视图层

}else{

throw new Exception(”数据模型不存在“);

}

}

}

?>

常量MBILE_MODEL定义了模型存放的目录名,在这里做了定义方便日后模型目录的需求更改。这是个良好的习惯。能统一定义的信息就该统一。能模块化的业务逻辑就应该模块化。为日后的项目维护和项目扩展做好铺垫。

MBILE_MODEL在Config/ __Active.php文件里面这样定义:

<?php

/**

系统配置

*/

define(’MOBILE_ROOT’, ”); //站根目录

define(’MOBILE_MODEL’,'Modules’); //模型目录名

?>

class_exists() 函数来判断客户请求的($_REQUEST['m']) 模型类是否存在。Class_exists() 方法依据__autoload() 函数来加载判断。所以__autoload()函数必须在class_exists() 方法之前先加载。

模型类如果存在,就使用method_exists() 方法来判断执行模型类里面的model 方法里面的业务逻辑,然后再执行show() 方法显示视图。这样就完成了一个 MVC 流程。

存放模型的目录是 Modules 目录。这个在上面的MOBILE_MODEL 常量中已经定义。难道所有的业务模型都存在在一个Modules目录里面吗?这样的设计的确有点问题。文件夹里面的文件过多,损耗程序寻找模型加载的时间,而且模型过多存在一个目录之中,会让这个项目变得很杂乱。比如前台和后台的模型目录和视图目录就应该分开存放。

<?php

/**

多模型目录

*/

if(empty($_GET['c']) && ) $_GET['c'] = ‘Default’;

if(empty($_GET['m'])) $_GET['m'] = ‘Index’;

define (’MODEL_SWITCHING’,$_GET['c']) ; //前台后台目录切换

?>

常量MODEL_SWITCHING 就是为解决这个问题设计的:

我们先看最后一句代码:

define (’MODEL_SWITCHING’,$_GET['c']) ; //前台后台目录切换

它定义了常量MODEL_SWITCHING 以$_GET ['c'] 变量为值。App_Run 类中,常量MOBILE_MODEL 、MODEL_SWITCHING 和$_GET['m'] 组成了模型的加载路径:

$model = MOBILE_MODEL.’_’.MODEL_SWITCHING.’_’.$_GET['m'];

这样设计以后我们想添加多个模型目录是很容易的事情了。比如项目需要添加两个模型目录。前台模型目录:Default 和 后台模型目录:Admin 。只需要在默认的模型目录 Modules 下创建 Default 和Admin 两个目录。然后客户访问的URL 中 添加一个 参数c :

访问Default 目录下的Myblog业务模型: index.php?c=default&m=myblog

访问Admin 目录下的Member业务模型: index.php?c=admin&m=member

我们可以再设计灵活人性化点,就是当$_GET[‘m’]和$_GET[‘c’] 客户没有设置的时候来给模型目录和业务模型类设置一个默认值。

if(empty($_GET['c']) ) $_GET['c'] = ‘Default’;

if(empty($_GET['m'])) $_GET['m'] = ‘Index’;

控制器

PHP MVC典型的设计就是使用单入口php文件来实现MVC中的C:控制器。所有的客户请求全部经过index.php 控制器集中控制。然后按需进行分发:

<?php

/**

入口文件

*/

try{

error_reporting(E_ALL); //关闭错误输出

require ‘Config/__Homeswitching.php’;

require ‘Config/__Active.php’;

require ‘App/Auto.php’;

$set = new App_Run;

$set->routing();

}catch (Exception $e){

echo($e->getMessage());

}

?>

多模型设置文件:__Homeswitching.php,定义基础模型目录文件:__Active.php,类驱动文件:Auto.php

加载完后,再实例化模型路由App_Run类,执行其 routing() 方法 寻找完成客户请求。

业务模型

业务模型类是整个项目中使用最多的。它就是MVC 中的M (模型)。类里面封装了大量的业务逻辑。比如:客户向index.php 控制器 请求 (index.php?m=newbook) newbook业务模型,来查询最新出的图书。 那么newbook业务模型类所需要完成的任务就是查询数据库,从数据库中提取最新的图书资料,然后发送到 视图层(View)显示给客户。显然,MVC 模式可以把 模型与模型,功能与功能之间的耦合度变得很小,扩展性很强。

<?php

/**

* 模型类

* */

class Modules_Default_Index extends App_Manage

{

private newbook=’’;

public function __construct(){

parent::__construct();

}

public function show(){

$this->tpl->assign(‘newbook’,$this->newbook);

$this->tpl->display(’Index’);

}

public function model(){

/**实现业务逻辑*/

$this->newbook = ‘PHP MVC’;

}

}

?>

业务模型类里面有两个主要方法: model() 、show() 方法。Model() 方法主要实现业务逻辑,比如:读数据库,写数据库等。Show() 方法主要和model() 方法联系获取业务逻辑的数据,然后输出给视图(php模板)。

读者请思考下以下几个问题:

模型类 Modules_Default_Index 为什么要起这个名字?前面__autoload讲解中已讲解。Show() 方法是否能去掉只实现model() 模型?模型的路由小节中讲解。

全局类

在项目开发里,有很多我们自己封装好的类:数据库操作类、模板类、email发送类、分页类、文本缓存类、内存缓存类memcache等等。这些类中有些是每个模型都必须加载使用的,比如 数据库操作类、分页类。难道我们每个模型里都要显式的实例化一次?那真是太麻烦了。所以设计一个全局管理类App_Manage :

<?php

class App_Manage{

protected $tpl;

protected $mem;

protected $email;

public function __construct(){

$this->tpl = new Lib_Tpl;

/* $this->mem = new Lib_Memcached;

$this->email = new Lib_Mailer();*/

}

}

?>

在App_Manage中。我们简单的在其构造方法中实例化了几个常用的类。每个模型都继承App_Manage类,这样模型类里面就可以使用父类的方法和属性,以此实现全局类:

public function __construct(){

parent::__construct();

}


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值