`
baiyuxiong
  • 浏览: 174680 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

论PHP框架设计模式及MVC的缺陷

    博客分类:
  • php
阅读更多
请勿转载。

目前主流的PHP框架设计模式均为MVC模式,比如yii或codeigniter,均是由控制器接收页面请求,并沟通模型与视图的交互。如果我们把网站整体看作一个矩阵,把网站接收用户请求并处理看作是网站的竖向,而把网站的每一个模块(比如文章模块,投票模块,论坛模块等)看作是网站的横向。那么我们可以画出这样的图:

               模块1  模块2 模块3
用户请求 ----------------------
                |      |      |
                |      |      |
数据处理 ----------------------
                |      |      |
                |      |      |
页面呈现 ----------------------

MVC的缺陷
MVC模式,侧重于竖向即请求、处理、呈现之间的协调,而忽略了模块之间的协调,从图里我们可以看出,当用户发起请求的时候,由哪个模块来处理用户的请求已经确定了,这就使模块之间呈现非常强的独立性,这该怎么理解呢,举个例子来说。
假设现在,你有两个模块,一个是新闻模块,一个是图片模块,新闻模块展示一些新闻文章,图片模块用来展示图片。
如果用MVC,我们这样实现:定义两个控制器news,pic,两个模型news_model,pic_model,两个视图news_view,pic_view,当有用户请求news控制器时,先调用news_model取得需要的数据,再用这些数据渲染news_view,最后呈现给用户。
有一天,你的领导忽然有了新想法,HEY,伙计,新闻模块只显示新闻太单调,让新闻模块,能显示图片模块里最热门的图片。这下不好办了,new_model里没有图片相关的模型,news_view里也没有显示图片列表的视图。你有解决办法?把显示图片列表相关的模型和视图分别复制一份到news的模型和视图?不,这么做不好,如果我现在全站都要显示热门图片列表你怎么办?还复制吗?不可以的。后期维护会累死人。
在codeigniter框架里,有更好一点儿的解决办法,就是把显示图片列表这个功能做成一个library,每需要的地方,调用library就可以,因为library有与控制器相同的沟通模型视图的功能。但这会带来一个新的问题:数据共享,如果页面分割成不同的library来实现,不同的library的数据很难共享,library之间是完全独立的。
现在来看,这一切的一切都是因为mvc模式注重竖向的沟通,而忽略了横向的沟通,完全割裂了模块之间的关系。

模块沟通
TextPattern(简称TXP)是一个小型的BLOG系统,它最大的特点是注重模块之间的沟通,完全模糊了不同模块间的界限,对与用户的一个请求,TXP完全没必要知道用户请求的是什么模块,新闻还是图片,只需要知道请求的页面要呈现些什么功能点。每一个小功能点都是完全独立的。
这是一种视图驱动的模式,接收到用户请求后,首先取到要请求的视图,视图文件再调用不同的功能点,这样就弱化了模块之间独立性。通俗点儿说:用户想看什么,你就给什么,不要管它是不是同一个模块,是不是有关系。wordpress也是基于视图驱动的模式的。


HMVC
层叠式的MVC,这是MVC模式的升级版本。首先把系统按功能点分,每个功能点的实现再采用MVC模式。HMVC同时兼顾了横向和竖向的沟通。

我所认为理想的模式
基于视图驱动的HMVC,基于视图驱动,就是以用户为基础,呈现用户想看到,以需求为驱动才是正确的。HMVC保证了代码的重用,易于维护。
视图驱动,可以借鉴WORDPRESS的实现,因为wordpress的模板开发、替换很容易;横向沟通的实现可以借鉴TXP;竖向沟通就是典型的MVC了。

一家之言,欢迎拍砖。请勿转载。
分享到:
评论
30 楼 renzhen 2011-04-22  
vb2005xu 写道
套用r大大那句话: 使用rails或者PHP类rails框架的 基本都是充血模型 想瘦都瘦不下来

使用 java ssh 基本就是 贫血模型 你想充也充不了 PHP的 怎么简单就怎么来好了 只要能 代码看的舒服 就怎么来 干嘛自己整那么多规矩

充血模型和贫血模型是相对于Model层而言的,而PHP框架里争议最大的似乎就是M层,一来无法实现rails那样强大的Model功能,即使实现了性能也是惨不忍睹。二来不符合长久以来PHP基于SQL的开发习惯,老实说,习惯这东西是十分强大的,曾经有一个外国人写了一篇blog,讲从Rails转回PHP开发他的网站,其中一个主要原因就是不习惯ActiveRecord的操作,习惯SQL语言开发。
29 楼 vb2005xu 2011-04-22  
昨天写程序遇到某些问题 想了一宿 突然想通了 之前是我太浅薄了 呵呵 收回之前所有的话 我就是个新手

thanks楼主 你的这个 视图驱动 解决了 我长期困扰的一个问题 呵呵 我要好好想想 然后改善我的 sfw ..

这个问题 我之前也遇到过 ... 在qee的里面 视图层 在一定程度上使用 控件 也解决了这个问题

不过你这种 视图驱动 开发的 建议 很好 , 我要好好想想了 谢谢了啊

28 楼 baiyuxiong 2011-01-31  
dwwind 写道
vb2005xu 写道
dwwind 写道
当前的php框架,都是喜欢大而全,而不是只提供一个基本的架子(基础)。
前些日子,接手一个项目用了ci,感觉不过如此。
我认为M层就应该是与框架无关的,但是很多php框架偏偏不!
你的struts框架的service层只能被特定的C用吗?当然不是了。

当然,写个php 框架也不是什么难事,可以自己试试,对mvc应该会有更深的了解!


一看就知道是PHP新手


:-) 不错!我写php尚不到3年。也用过一些框架。
   每个人对框架的理解可能不一样。自己用着顺手的才是最好的。
   日前也曾经写了个:http://rare.sinaapp.com.
 
   呵呵,现在php框架已经快到了一个泛滥的程度了。

嗯,也许自己写的才是最顺手的……
回头研究一个自己的。
27 楼 vb2005xu 2011-01-20  
套用r大大那句话: 使用rails或者PHP类rails框架的 基本都是充血模型 想瘦都瘦不下来

使用 java ssh 基本就是 贫血模型 你想充也充不了 PHP的 怎么简单就怎么来好了 只要能 代码看的舒服 就怎么来 干嘛自己整那么多规矩
26 楼 dwwind 2011-01-19  
vb2005xu 写道
dwwind 写道
当前的php框架,都是喜欢大而全,而不是只提供一个基本的架子(基础)。
前些日子,接手一个项目用了ci,感觉不过如此。
我认为M层就应该是与框架无关的,但是很多php框架偏偏不!
你的struts框架的service层只能被特定的C用吗?当然不是了。

当然,写个php 框架也不是什么难事,可以自己试试,对mvc应该会有更深的了解!


一看就知道是PHP新手


:-) 不错!我写php尚不到3年。也用过一些框架。
   每个人对框架的理解可能不一样。自己用着顺手的才是最好的。
   日前也曾经写了个:http://rare.sinaapp.com.
 
   呵呵,现在php框架已经快到了一个泛滥的程度了。
25 楼 hcw1314520 2011-01-19  
我们是将model层分为两层:DAO和SERVICE
控制器调用自己的SERVICE但是不同的SERVICE可以相互调用。
这样控制器就能通过SERVICE调用其他的服务了!
24 楼 vb2005xu 2011-01-18  
dwwind 写道
当前的php框架,都是喜欢大而全,而不是只提供一个基本的架子(基础)。
前些日子,接手一个项目用了ci,感觉不过如此。
我认为M层就应该是与框架无关的,但是很多php框架偏偏不!
你的struts框架的service层只能被特定的C用吗?当然不是了。

当然,写个php 框架也不是什么难事,可以自己试试,对mvc应该会有更深的了解!


一看就知道是PHP新手
23 楼 dwwind 2011-01-18  
当前的php框架,都是喜欢大而全,而不是只提供一个基本的架子(基础)。
前些日子,接手一个项目用了ci,感觉不过如此。
我认为M层就应该是与框架无关的,但是很多php框架偏偏不!
你的struts框架的service层只能被特定的C用吗?当然不是了。

当然,写个php 框架也不是什么难事,可以自己试试,对mvc应该会有更深的了解!
22 楼 baiyuxiong 2010-12-23  
dwangel 写道
baiyuxiong 写道
我知道控制器可以调用类库或者调用别的控制器,不过这也没什么优势,在视图里面没办法调用别的控制器。

看来楼主是觉得MVC在代码重用上不方便。
楼主是不是用过 asp.net开发项目,习惯了那里的页面控件里也嵌入逻辑的模式。

这个只是开发时思考习惯问题。

楼主是想从最终页面 看有几个视图,然后根据视图考虑显示一个完整页面需要执行哪些逻辑。
这个基于一个前提,这个View是跟逻辑密不可分的。

如果这样的话,codeigniter 我不熟,但刚看了文档,可以把逻辑写成在library里的一个类,由这个逻辑负责调用相应的视图。
abstract public class ViewLogic{
  protected $controller;
  public __constructor($controller) {
    $this->controller = $controller;
  }
  public function execute() {
    doTask();
    $this->controller->loadView($this->getViewName());
  }
  abstract protected function doTask();
  abstract protected function getViewName();
}
public class NewsViewLogic {

  public function getViewName() { return "NewsView"; }
  public function doTask() {
    .....
  }
}

在控制器里仅仅是调用library。
$this->load->library('NewsViewLogic', array('controller'=>$this) );
$this->newsviewlogic->execute();

你有几个页面要用NewView,就copy几个调用字段就行。
甚至可以这样:
$logics = array("NewsViewLogic", "ddddLogic");
foreach($logics as $logic) {
  $this->load->library($logic, array('controller'=>$this) );
  $logicName = strtolow($logic);
  $this->$logicName->execute();
}

做个基类,把循环部分放到公用方法也行。
每个页面的Controller也就是配配 $logics 了。
以上代码只是示意,未经测试。


嗯,这种做法不错,学习了。
我发现我写程序总是用面向过程的思想写面向对象的程序
这个思维习惯真难改。
21 楼 baiyuxiong 2010-12-23  
vb2005xu 写道
你可以看看 QEEPHP框架 或者 我写的 xser php 框架

有什么特别之处呢?
20 楼 vb2005xu 2010-12-23  
你可以看看 QEEPHP框架 或者 我写的 xser php 框架
19 楼 vb2005xu 2010-12-23  
baiyuxiong 写道
lxholding 写道
baiyuxiong 写道
smilerain 写道
lz 对 mvc的理解很清晰,不过感觉不能灵活的使用,所以才会碰到这些问题。
利用好逻辑接口,配合view部分的继承关系,view不一定是一个页面,也可以是一个区域。MVC只是一个构架概念,自己的程序能够清晰的分层利于维护就算可以了。


明白了,我的理解太局限于CI这个框架了,因为我用这个框架用的多,把这个框架的缺点理解成MVC的缺点了。

yii或codeigniter的帮助和例子里的model层都是实体model,楼主应该是被这个误导了,在控制层完全能够调用自己的类干活


我知道控制器可以调用类库或者调用别的控制器,不过这也没什么优势,在视图里面没办法调用别的控制器。



在视图里面没办法调用别的控制器 ...

对这一句话 我有点异议: 你在这里为什么要调用控制器???/ 我很不解


视图里面 我认为 他就是 输出数据的模版 , 此处调用控制器 应该就是 连接或者 ajax请求的事情了 和视图又有什么关系


18 楼 dwangel 2010-12-21  
baiyuxiong 写道
我知道控制器可以调用类库或者调用别的控制器,不过这也没什么优势,在视图里面没办法调用别的控制器。

看来楼主是觉得MVC在代码重用上不方便。
楼主是不是用过 asp.net开发项目,习惯了那里的页面控件里也嵌入逻辑的模式。

这个只是开发时思考习惯问题。

楼主是想从最终页面 看有几个视图,然后根据视图考虑显示一个完整页面需要执行哪些逻辑。
这个基于一个前提,这个View是跟逻辑密不可分的。

如果这样的话,codeigniter 我不熟,但刚看了文档,可以把逻辑写成在library里的一个类,由这个逻辑负责调用相应的视图。
abstract public class ViewLogic{
  protected $controller;
  public __constructor($controller) {
    $this->controller = $controller;
  }
  public function execute() {
    doTask();
    $this->controller->loadView($this->getViewName());
  }
  abstract protected function doTask();
  abstract protected function getViewName();
}
public class NewsViewLogic {

  public function getViewName() { return "NewsView"; }
  public function doTask() {
    .....
  }
}

在控制器里仅仅是调用library。
$this->load->library('NewsViewLogic', array('controller'=>$this) );
$this->newsviewlogic->execute();

你有几个页面要用NewView,就copy几个调用字段就行。
甚至可以这样:
$logics = array("NewsViewLogic", "ddddLogic");
foreach($logics as $logic) {
  $this->load->library($logic, array('controller'=>$this) );
  $logicName = strtolow($logic);
  $this->$logicName->execute();
}

做个基类,把循环部分放到公用方法也行。
每个页面的Controller也就是配配 $logics 了。
以上代码只是示意,未经测试。
17 楼 keete 2010-12-21  
回复是亮点。。
16 楼 zuowj 2010-12-20  
squall2825 写道
其实说句实话,很多程序员都知道MVC,但很多程序员(包括我在内)都不非常透彻的理解MVC,从JAVA提倡MVC框架开始到PHP的开发,有很多程序员都只是在开发框架的模式下进行所谓MVC的分层,个人认为只熟悉MVC框架并不等于真正了解MVC概念,好比古人习武,每招每式都已经模仿的非常淋漓尽致可却总无法成为真正的高手,原因在于自身已经被某套武功所局限,从而无法真正理解到武功的真谛,所谓宗师与凡人的区别在于宗师能在一套凡人看似非常完美的武功中看出其优劣点,并能根据其特点从而进行改进,其实程序也应该是如此,从刚开始学到现在,感觉自己越来越菜,不像以前那样直观和清晰了,也是因为框架用多了,思维被模式化了,很多东西还是需要靠自己来打破这种陈规,世上本来没有路,走的人多了自然就成了路。希望写这些东西能对大家有用。


说下我的理解:
  MVC是现在WEB系统设计的主流模式,它背后的思想是"交互界面与逻辑的分离

做到良好分离,这样就可以:

    一份逻辑代码可以支持不同的展现(不同数据项、不同展现技术、 不同展现终端)
    展现界面及交互休验的改进,不用受制于逻辑代码的开发周期
    逻辑开发者(服务端工程师)与界面交互开发者(前端工程师)能专注和发挥优势。

当然这种思想不仅在WEB开发领域才有体现,在客户端开发也有体现。

而MVC的框架主要解决的问题就是: 在开发时,提供展现与逻辑分离的组织结构;在在运行时,提供两者灵活结合的机制。


15 楼 liguomin 2010-12-17  
[quote="squall2825"]其实说句实话,很多程序员都知道MVC,但很多程序员(包括我在内)都不非常透彻的理解MVC,从JAVA提倡MVC框架开始到PHP的开发,有很多程序员都只是在开发框架的模式下进行所谓MVC的分层,个人认为只熟悉MVC框架并不等于真正了解MVC概念,好比古人习武,每招每式都已经模仿的非常淋漓尽致可却总无法成为真正的高手,原因在于自身已经被某套武功所局限,从而无法真正理解到武功的真谛,所谓宗师与凡人的区别在于宗师能在一套凡人看似非常完美的武功中看出其优劣点,并能根据其特点从而进行改进,其实程序也应该是如此,从刚开始学到现在,感觉自己越来越菜,不像以前那样直观和清晰了,也是因为框架用多了,思维被模式化了,很多东西还是需要靠自己来打破这种陈规,世上本来没有路,走的人多了自然就成了路。希望写这些东西能对大家有用。

说得很透彻,我也有这种感觉,开发的时候只是在进行着所谓的MVC分层,而至于其中的概念至今都感觉不能完全理解。
14 楼 squall2825 2010-12-16  
其实说句实话,很多程序员都知道MVC,但很多程序员(包括我在内)都不非常透彻的理解MVC,从JAVA提倡MVC框架开始到PHP的开发,有很多程序员都只是在开发框架的模式下进行所谓MVC的分层,个人认为只熟悉MVC框架并不等于真正了解MVC概念,好比古人习武,每招每式都已经模仿的非常淋漓尽致可却总无法成为真正的高手,原因在于自身已经被某套武功所局限,从而无法真正理解到武功的真谛,所谓宗师与凡人的区别在于宗师能在一套凡人看似非常完美的武功中看出其优劣点,并能根据其特点从而进行改进,其实程序也应该是如此,从刚开始学到现在,感觉自己越来越菜,不像以前那样直观和清晰了,也是因为框架用多了,思维被模式化了,很多东西还是需要靠自己来打破这种陈规,世上本来没有路,走的人多了自然就成了路。希望写这些东西能对大家有用。
13 楼 baiyuxiong 2010-12-15  
等天上掉大饼 写道

楼主的说法比较费解。

news的controller只能调用new_model?

它也可以调用pic_model啊

嗯,调用model是可以的,但是调用pic_view就不方便了吧?
12 楼 等天上掉大饼 2010-12-14  

楼主的说法比较费解。

news的controller只能调用new_model?

它也可以调用pic_model啊
11 楼 nakupanda 2010-12-11  
感觉PHP用最直观的过程式开发方式是最好的了

相关推荐

Global site tag (gtag.js) - Google Analytics