xylxq1925

写完那篇“写给懂C语言的人的PHP基本语法入门”后一直在学习PHP5的OOP,目的很简单,就是想研究MVC的PHP实现,所以,兴趣很快转移到 MVC上面,网上有很多长篇大论,但是看完了我还是不能写出一个最简单的MVC程序,我这个人学东西有个习惯,那就是先要掌握一个最简单的“Hello World”,然后再以此为基础扩展开去,否则心里没底,一头雾水。
经过一番搜索,找到了一篇翻译文章(作者:Harry Fuecks 翻译:Easy Chen URL:http://www.21ds.net/article/4/453 原文URL:http://www.phppatterns.com/docs/ ... _controller_pattern)作者以商品目录浏览为例,给出了完整的MVC架构代码。仔细一看,发现他的C和V是继承关系,耦合很紧,似乎不是很理想,但马上又看到了作者的第二个版本(http://www.phppatterns.com/doku.php/design/mvc_pattern_version_2),这个版本的C和V分离得比较清楚,仔细研读了这个版本,然后仿照着实现了一个留言板。
标题上我把这个留言板叫最简单的,其实应该叫最简陋的,因为把全部注意力集中在MVC模式设计和实现上,所以UI方面几乎没有一点修饰。之所以在这里跟大 家分享这个东西,是因为我自己通过读该老外的代码并仿照着写留言板对MVC的概念和具体实现有了些认识,希望了解MVC具体实现的朋友可以参考一下。
首先通俗地说说我对MVC的理解:Model是负责干活的,它干的活主要是从数据库中获取需要的数据以及对获取的数据按照业务逻辑进行加工处理,至于为什 么要干某件活,何时干某件活它一概不管,而这正是Controller的职责,Controller像个餐馆招待,接到食客的需求,马上传达给厨 房,Model就是大厨。View负责最终把菜端上桌,摆在合适的位置上。比如说客人来了要了个糖醋鲤鱼,接待客人的是Controller,它会通知 Model做一道糖醋鲤鱼,做好之后它又会招呼View把菜端上桌,View知道这是主菜,它会把它摆在桌子中央。MVC的最大优势就在于把数据处理、流 程控制和UI显示较好地分离开来,便于程序的开发和维护。
好了,下面看具体实现。
这个小程序一共包含6个文件,其中index.php是程序入口、post.htm是留言表单、在lib文件夹里Model、View 、Controller三个文件分别实现MVC,DataAccess是一个简单的数据库访问类。 复制PHP内容到剪贴板 PHP代码:
 /**
* 一个用来访问MySQL的类
* 仅仅实现演示所需的基本功能,没有容错等
* 代码未作修改,只是把注释翻译一下,加了点自己的体会
*/
class DataAccess
{

var
$db;
//用于存储数据库连接

var $query;
//用于存储查询源

//! 构造函数.
/**
* 创建一个新的DataAccess对象
* @param $host 数据库服务器名称
* @param $user 数据库服务器用户名
* @param $pass 密码
* @param $db 数据库名称
*/
function __construct($host,$user,$pass,$db
) {
$this->db=mysql_pconnect($host,$user,$pass);
//连接数据库服务器
mysql_select_db($db,$this->db);
//选择所需数据库
//特别注意$db和$this->db的区别
//前者是构造函数参数
//后者是类的数据成员
}

//! 执行SQL语句
/**
* 执行SQL语句,获取一个查询源并存储在数据成员$query中
* @param $sql 被执行的SQL语句字符串
* @return void
*/
function fetch($sql
) {
$this->query=mysql_unbuffered_query($sql,$this->db);
// Perform query here
}

//! 获取一条记录
/**
* 以数组形式返回查询结果的一行记录,通过循环调用该函数可遍历全部记录
* @return mixed
*/
function getRow
() {
if (
$row=mysql_fetch_array($this->query,MYSQL_ASSOC
) )
//MYSQL_ASSOC参数决定了数组键名用字段名表示
return $row
;
else
return
false
;
}
}
?>


下面再来介绍一下Model类。
这个类也很简单,里面的函数一看就知道,是针对各种数据操作的,它通过DataAccess访问数据库。 复制PHP内容到剪贴板 PHP代码:
//! Model类
/**
* 它的主要部分是对应于留言本各种数据操作的函数
* 如:留言数据的显示、插入、删除等
*/

class Model
{

var
$dao;
//DataAccess类的一个实例(对象)

//! 构造函数
/**
* 构造一个新的Model对象
* @param $dao是一个DataAccess对象
* 该参数以地址传递(&$dao)的形式传给Model
* 并保存在Model的成员变量$this->dao中
* Model通过调用$this->dao的fetch方法执行所需的SQL语句
*/
function __construct(&$dao
) {
$this->dao=$dao
;
}

function
listNote() {
//获取全部留言
$this->dao->fetch("SELECT * FROM note"
);
}

function
postNote($name,$content) {
//插入一条新留言
$sql =
"INSERT INTO `test`.`note`
(`id`, `name`, `content`, `ndate`, `add`)
VALUES (NULL, \'$name\', \'$content\', NULL, NULL);"
;
//echo $sql; //对于较复杂的合成SQL语句,

//调试时用echo输出一下看看是否正确是一种常用的调试技巧
$this->dao->fetch($sql
);
}

function
deleteNote($id) {
//删除一条留言,$id是该条留言的id
$sql = "DELETE FROM `test`.`note` WHERE `id`=$id;"
;
//echo $sql;
$this->dao->fetch($sql
);
}


function
getNote() {
//获取以数组形式存储的一条留言
//View利用此方法从查询结果中读出数据并显示
if ( $note=$this->dao->getRow
() )
return
$note
;
else
return
false
;
}
}
?>


看完这两个类之后你可能会发现这与以前我们写程序差不多,的确现在还闻不到MVC的味道,如果你不懂MVC,在这两个类的基础上你完全可以开始写你以前的程序了。例如要显示全部留言,只需要写入下代码: 复制PHP内容到剪贴板 PHP代码:
require_once(\'lib/DataAccess.php\');
require_once(
\'lib/Model.php\'
);

$dao=& new DataAccess (\'localhost\',\'root\',\'\',\'test\'
);
$model=& new Model($dao
);
$model->listNote
();

while (
$note=$model->getNote
())
{
$output.="姓名:$note[name]
留言:
$note[content]


";
}
echo
$output
;
?>


很亲切吧,呵呵。
有了这个“感情基础”你就不会对MVC望而生畏了,下面我们就要上今天的主菜了,那就是“Controller”闪亮登场!
先大体浏览一下主要结构,它包括一个Controller类以及派生出的三个子类(listController对应显示留言功能、 postController对应发表留言功能以及deleteController对应删除留言功能)。 复制PHP内容到剪贴板 PHP代码:

//! Controller
/**
* 控制器将$_GET[\'action\']中不同的参数(list、post、delete)
* 对应于完成该功能控制的相应子类
*/

class Controller
{
var
$model;
// Model 对象
var $view;
// View 对象

//! 构造函数
/**
* 构造一个Model对象存储于成员变量$this->model;
*/
function __construct (& $dao
) {
$this->model=& new Model($dao
);
}


function
getView() {
//获取View函数
//返回视图对象view
//对应特定功能的Controller子类生成对应的View子类的对象
//通过该函数返回给外部调用者
return $this->view
;
}


}

//用于控制显示留言列表的子类
class listController extends Controller{
//extends表示继承

function __construct (& $dao
) {
parent::__construct($dao);
//继承其父类的构造函数
//该行的含义可以简单理解为:
//将其父类的构造函数代码复制过来
$this->view=& new listView($this->model
);
//创建相应的View子类的对象来完成显示
//把model对象传给View子类供其获取数据
}
}

//用于控制添加留言的子类
class postController extends Controller
{

function
__construct (& $dao, $post
) {
parent::__construct($dao
);
$this->view=& new postView($this->model, $post
);
//$post的实参为$_POST数组
//表单中的留言项目存储在该系统数组中
}
}

//用于控制删除留言的子类
class deleteController extends Controller
{
function
__construct (& $dao, $id
) {
parent::__construct($dao
);
$this->view=& new deleteView($this->model, $id
);
}
}
?>


大体浏览之后,你一定打算开始仔细研究它了吧,别急,为了心中有数,我们先从宏观着眼,先看看总入口index.php是如何调用Controller的: 复制PHP内容到剪贴板 PHP代码:<html>
<
head
>
<
meta http-equiv="Content-Type" content="text/html; charset=gb2312"
/>
<
title>PHP MVC留言板title
>
head
>
<
body
>
<
a href="post.htm">添加新留言a><br
>
<
p
>

php
//!index.php 总入口
/**
* index.php的调用形式为:
* 显示所有留言:index.php?action=list
* 添加留言 :index.php?action=post
* 删除留言 :index.php?action=delete&id=x
*/
require_once(\'lib/DataAccess.php\'
);
require_once(
\'lib/Model.php\'
);
require_once(
\'lib/View.php\'
);
require_once(
\'lib/Controller.php\'
);
//创建DataAccess对象(请根据你的需要修改参数值)
$dao=& new DataAccess (\'localhost\',\'root\',\'\',\'test\'
);
//根据$_GET["action"]取值的不同调用不同的控制器子类
$action=$_GET["action"
];

switch (
$action
)
{
case
"post"
:
$controller=& new postController($dao,$_POST
); break;
case
"list"
:
$controller=& new listController($dao
); break;
case
"delete"
:
$controller=& new deleteController($dao,$_GET["id"
]); break;
default:
$controller=& new listController($dao); break;
//默认为显示留言

}

$view=$controller->getView();
//获取视图对象
$view->display();
//输出HTML
?>



看过index.php之后你就更清楚了吧,原来功能是通过$_GET[“action”]指定的,由一个switch结构分发,不同的功能对应 不同的Controller子类。现在可以滚上去(滚动页面上去的简称,绝非不洁用语^_^)仔细看看这个Controller代码了。注释应该很细了, 不懂的地方就去看看PHP5的OOP语法和概念吧,单纯看这些概念总是越看催眠效果越好,现在带着实际问题去看,应该有所不同吧。不过我还是建议你在完成 这个MVC的Hello World知道MVC是怎么回事之后下功夫打好OOP的基础,毕竟那是根本啊。
怎么样,Controller真是个光说不练的家伙吧,看不到三行它就把你引向View了,那就看看View吧。
View里有对应的子类,负责相应功能的显示。理解了Controller,View的代码就不难看了,难看的话也是因为混杂着HTML的原因,它所做的就是从Model获取所需的数据,然后塞到HTML中。 复制PHP内容到剪贴板 PHP代码:
//! View 类
/**
* 针对各个功能(list、post、delete)的各种View子类
* 被Controller调用,完成不同功能的网页显示
*/
class View
{

var
$model;
//Model对象

var $output;
//用于保存输出HTML代码的字符串

//! 构造函数
/**
* 将参数中的Model对象接收并存储在成员变量$this->model中
* 供子类通过model对象获取数据
*/
function __construct (&$model
) {
$this->model=$model
;
}

function
display() {
//输出最终格式化的HTML数据
echo($this->output
);
}
}

class
listView extends View
//显示所有留言的子类
{
function
__construct(&$model
)
{
parent::__construct(&$model);
//继承父类的构造函数(详见Controller)
$this->model->listNote
();
while (
$note=$this->model->getNote())
//逐行获取数据
{
$this->output.=
"姓名:$note[name]
留言:
$note[content]
.$_SERVER[\'PHP_SELF\']."?action=delete&id=$note[id]\">删除

"
;
}
}
}

class
postView extends View
//发表留言的子类
{
function
__construct(&$model, $post
)
{
parent::__construct(&$model
);
$this->model->postNote($post[name],$post[content
]);
$this->output="Note Post OK!
.$_SERVER[\'PHP_SELF\']."?action=list\">查看"
;
}
}

class
deleteView extends View
//删除留言的子类
{
function
__construct(&$model, $id
)
{
parent::__construct(&$model
);
$this->model->deleteNote($id
);
$this->output="Note Delete OK!
.$_SERVER[\'PHP_SELF\']."?action=list\">查看"
;
}
}
?>


之所以UI方面写得如此简陋,是因为这些工作可以交给Smarty这样的模板去做,而我们这里就像集中精力研究MVC,不想把Smarty扯进来,所以就这样凑合了,以后我们可以再把Smarty结合进来。

看了这个东西之后不知你是否对MVC的概念和实现更明白了一点。
我也是个初学者,这是个依葫芦画瓢之作,目的就是想了解一下MVC,如果你是高手,我很想得到你的点评,这样的划分和架构是否符合MVC的理念?还有哪些应该改进之处?
当然,大家都知道现在很多关于MVC的争论,这很正常,就像关于开发语言的争论一样,永无休止,学术上的争论有助于创新。作为我们学技术、用技术而言,一 定要踏实深入学习,掌握了基本用法之后再去讨论,那才是更高层次的发展,在自己都搞不清的情况下在哪里争论只能是浪费时间。
下面说说我体会到的MVC的好处,它的确给程序的功能扩展带来方便,比如这个例子我们想要增加一个根据用户名查询留言的功能,只需要在Model里增加一 个查询函数(突然发现这些函数的用法很像存储过程),Controller和View里增加相应的子类,这种分离带来的好处是程序功能模块可以即插即用, 再就是整个程序的逻辑非常清晰。我想,对于需求变动频繁的Web应用来说,这种特性也许是很有价值的。

下面我们做什么呢?是不是再研究几个优秀的数据库操作库类,加深一下对数据库操作函数以及OOP的理解,然后再把Smarty整合进来?这方面坛子里的feifengxlq版主有很好的帖子http://bbs.phpchina.com/viewthread.php?tid=5687,应该好好学习一下。

URL:http://www.lampbrother.net/bbs/read-htm-tid-5231.html

分类:

技术点:

相关文章: