PHP和MVC的结合思想

我彻底摆脱 MVC 的束缚

之所以采用这么一条看上去很自大狂的标题, 目的不是要宣扬个人主义, 而是因为如果把标题的"我"去掉, 就变成我在鼓动大家不要 MVC, 那么我很可能沦为镖靶. 在某种程度上来说, MVC 确实有着积极的意义, 在我心目中 MVC 也曾经是先进的生产方法. 但是, 在 PHP-WEB 开发的世界中, 还有没有更先进的方法呢? 我是本着这个理念去思考和摸索的. 所以本文是一篇探索新路, 开拓新思维的文章, 是本着和诸君共勉的精神而写的, 请各位 MVC 的拥护者稍安毋燥, 和某著名"工业级"模板引擎的专家们不要对号入座, 先冷静地思考一下, 世界上除了模板引擎, 是否还存在更先进的开发方法?

在 Ruby on Rails 出现之前, 我并不知道 Web 开发中的 MVC 应该是什么样子. PHPE 有几篇文章倒是讨论过, 其中也有分歧. 直到我学了 RoR, 以及看了 PHP 世界中崛起的几个仿制品, 我才清楚 MVC 在 Web 开发中的样子. 一度我也认为这是极其聪明的办法. 但是最近我又琢磨出一种代替 MVC 的开发方法, 并且认为把 MVC 用在 PHP 开发上其实算不上聪明. 那么, 不论现在天天 MVC 的, 还是不太认识 MVC 的同学们, 我都先来显摆一下, 说说 Web 开发中的 MVC 是怎么一回事.

MVC 最初是从桌面应用开发中提出来的, 最先提出 MVC 的是 Smalltalk, 后来主流的 OO 开发都接受了 MVC 思想. 而 Web 开发中的 MVC 我想应该是从 Java 阵营中来的(这个我不是很确定), 这里我主要说 RoR 和 CakePHP 中的 MVC 模式, 据说它们的 MVC 模式就是从 Java 中偷来. Ruby on Rails 和 CakePHP 都是拿一个 controller 作为程序的入口, 这个 controller 会包含一个或若干个 models, 每一个 model 都是由一个独立的类实例化出来的, 大部分是 ORM 对象, 和小部分并不对应数据表, 而是用来分担一部分 controller 责任的"模型". 每一个 controller 又会有若干的 action, 每个 action 是一个函数, 分别对应一个 view, 也就是"模板". 程序的每一次执行会化为一个 url, 比如 index.php?controller=home&action=index, 这代表程序将实例化 HomeController 并执行其中的函数 index, 然后包含一个"模板"文件 index, 函数 index 则会把数据变量 set 到模板里面去, 于是我们就看到一个页面. 这一切看上去真是完美无缺, 一个 OO 狂热者必定会为它击节叫好.

但是在 Web 开发中, 特别是在 PHP-Web 开发中, MVC 真的有那么好吗?

我上面提到过, MVC 是由 Smalltalk 阵营提出, 在其它 OO 语言特别是 Java 阵营中遍地开花的. 然而 Smalltalk 和 Java 都是面向对象语言, 而 PHP 本质上是过程式语言, 过程式语言可以比面向对象式语言更加简练.

从一个 action 中把变量 set 进 view 中, MVC 模式是这么传递变量的. 当然 PHP 完全可以这么干, 但是可以更简单, 我的答案您可能会嗤之以鼻, 我的方法就是----全局变量. 从一个 OO 狂热者的角度来看, 全局变量是愚不可及的, 它总是四处破坏封装. 但是 PHP 是一种过程式的语言, 换一种角度来看, 只要代码长度总是可以控制, 全局变量和全局函数铁定比 OO 和 MVC 要省事得多. 基于"代码长度决定项目的开发和维护成本"的原则, 我决定寻找一种能代替 MVC 的模式. 下面阐述我的模式----OO 与 PO 混合仿 MVC 又看不出 MVC 的新模式.

Web 程序总是由 url 触发的, 世界上没有一只鼠标可以同时点击两个链接, 因此对同一个用户来说, Web 程序没有并发进程. 换句话说, MVC 中的同一个 controller 中的不同 action, 它们表现为两个不同的 url, 它们的执行过程是互不相干的.

假设 Web 程序的通用入口是 index.php, 我从这里开始介绍我的模式.



这是我的 index.php 中的主要部分, 其它一些琐碎代码都是围绕这个中心进行的. 我定义了 2 个重要变量 $app 和 $action, 默认值是 home 和 index. 如果用户访问网站的根目录, 就执行 ./apps/home/home_entrance.php, 接着运行 ./apps/home/index.php. 在这里 ./apps/home 整个目录代表传统 MVC 模式的整个 controller 及其所有的 views 的集合, 但是没有类, 只有一个个的子过程, 这就是"OO 与 PO 混合仿 MVC 又看不出 MVC 模式"的主要构成. home_entrance.php 是整个网站的首页入口, 比较复杂, 下面跳到另一个 url 来看看.

假设用户点击 index.php?app=admin, 进入管理页面需要登录, 我在 ./apps/admin/admin_entrance.php 中写:



这段代码等于传统 MVC 模式中 AdminController 类中的构造器, 也可以是 Rails 中的一个 before_filter, 不同之处是代码少了很多. 它的作用是把关, 影响全局变量 $action, 把不合法的访问导向 login 页面. 我也可以加入一句 $layout = 'admin', 这样页面输出也会被导向另一种风格.

下面看看 ./apps/admin/login.php



熟悉 RoR 和 Cake 的同学对代码中的两个函数 flash() 和 redirect_to() 必定不会陌生, 它们是贯穿整个项目的全局函数(我看不出有让它们从属于某个类的必要). $user = $User->new() 这一句是我的独门秘技 QiQ 做出来的一套 ORM, 用其它的 ORM, 你可以写 $user = new User, 而 $User->select() 可以是 User::select(). 比较触动某些人的神经的可能是我的 PHP/HTML 混写风格. 是的, 我是混写了, 但是我把传统 MVC 模式的 action 和对应的 view 放在一块儿, 并非混合了业务逻辑和显示逻辑, 在这里我完全看不出分离 action 和 view 的必要. 函数 login() 和 authorize_user() 是扎扎实实的子过程, 并非实现某种功能的公共库, 它们的存在仅仅是为变量提供一层命名保护.

到这里已经可以暂时打住, 相信大家完全可以看出我的意图: 我把传统上非常复杂的 MVC 完完全全给过程化了. 过程式语言并非一无是处, 根据一个简单的约定, 我就完成了 MVC 模式非常复杂的实现. Java 们看见这样简单的实现, 肯定要眼红, 谁叫 Java 没有全局变量和全局函数呢?

但是全局变量和全局函数肯定也有短处, 所以要有一些约束. 我们可以统计一下 index.php 中出现的全局变量, 计有 $app, $action, $output_content, 和 $layout, 全局函数有 flash(), flash_out() 和 redirect_to(), 这些在 action 文件中不可再用, 这与类属性和方法不可重名是一样的.

如果把一个 app 目录看作一个大的 controller 的话, 那么甚至可以把 index.php 看作这个 controller 的一部分. 这样一来就非常清晰了, 我确实在进行 MVC, 但是你看不见 controller 类, 看不见 view 文件, 它们被我完全过程化了.

总结, "OO 与 PO 混合仿 MVC 又看不出 MVC" 模式的主要优点是:

1. 代码量大幅降低, 系统复杂度大幅降低, 间接地成本大幅降低
2. action 直接和 view 结合, 清晰度大幅上升
3. 把 "controller" 拆散成许多子过程, 有利于构建大型项目.
国内网站习惯把大量内容放在首页上, 如果用传统的 MVC 模式来构建首页, 由于所有 actions 集中于一个 controller 中, 导致 controller 过度复杂(可能有数十个 action). 分拆之后每个程序员可以负责若干 action, 更有利于协同开发.
4. 如果实在需要分离 view, 可以在 index.php 中增加一句


这样就可以把 view 分离出来交给美工人员去做.

以上就是我今天的发言.

转: http://club.phpe.net/index.php?act=ST&f=15&t=12212
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
10-28 209
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值