2000年2月2日星期三

MVCサンプル

该程序有6个文件,其中index.php是程序入口、post.htm是留言表单、在lib文件夹里Model、View 、Controller三个文件分别实现MVC,DataAccess是一个简单的数据库访问类。

PHP代码:

<?php // 一个用来访问MySQL的类 仅仅实现演示所需的基本功能,没有容错等
class DataAccess {
var $db; //用于存储数据库连接
var $query; //用于存储查询源

//! 构造函数 创建一个新的DataAccess对象
// $host:数据库服务器名称、$user:数据库服务器用户名、$pass:密码、$db:数据库名称
function __construct($host,$user,$pass,$db) {
//连接数据库服务器
$this->db=mysql_pconnect($host,$user,$pass);
//选择所需数据库,$db是构造函数参数,$this->db是类的数据成员
mysql_select_db($db,$this->db);
}
//! 执行SQL语句,获取一个查询源并存储在数据成员$query中 $sql 被执行的SQL语句字符串
function fetch($sql) {
$this->query=mysql_unbuffered_query($sql,$this->db); // Perform query here
}
//! 获取一条记录(MYSQL_ASSOC参数决定了数组键名用字段名表示)
// 以数组形式返回查询结果的一行记录,通过循环调用该函数可遍历全部记录
function getRow () {
if ( $row=mysql_fetch_array($this->query,MYSQL_ASSOC) )
return $row;
else
return false;
}
}
?>


下面再来介绍一下Model类。它通过DataAccess访问数据库进行各种数据操作的。

PHP代码:

<?php //! Model类 主要是对应于留言本各种留言数据的显示、插入、删除等操作的函数。
class Model {
var $dao; //DataAccess类的一个实例(对象)

//! 构造函数 构造Model对象 $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`) VALUES ($id, '$name');";
$this->dao->fetch($sql);
}
function deleteNote($id) { //删除一条留言,$id是该条留言的id
$sql = "DELETE FROM `test`.`note` WHERE `id`=$id;";
$this->dao->fetch($sql);
}
//获取以数组形式存储的一条留言View利用此方法从查询结果中读出数据并显示
function getNote() { 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]<br> 留言:<br> $note[content] <br> <hr />";
}
echo $output;
?>

下面我们就要上今天的主菜了,那就是“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); }
//对应特定Controller子类生成对应的View子类的对象返回给外部调用者
function getView() { return $this->view; }
}
//用于控制显示留言列表的子类
class listController extends Controller{
function __construct (& $dao) {
//继承其父类的构造函数
parent::__construct($dao);
//创建相应的View子类的对象来完成显示,把model对象传给View子类供其获取数据
$this->view=& new listView($this->model);
}
}
//用于控制添加留言的子类
class postController extends Controller{
function __construct (& $dao, $post) {
parent::__construct($dao);
//$post的实参为$_POST数组,表单中的留言项目存储在该系统数组中
$this->view=& new postView($this->model, $post);
}
}
//用于控制删除留言的子类
class deleteController extends Controller{
function __construct (& $dao, $id) {
parent::__construct($dao);
$this->view=& new deleteView($this->model, $id);
}
}
?>

为了心中有数,我们先从宏观着眼,先看看总入口index.php是如何调用Controller的:

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');

$dao=& new DataAccess ('localhost','root','','test'); //创建DataAccess对象(请根据你的需要修改参数值)
$action=$_GET["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
?>
</body>
</html>

看过index.php之后你就更清楚了吧,原来功能是通过$_GET[“action”]指定的,由一个switch结构分发,不同的功能对应不同的Controller子类。
怎么样,Controller真是个光说不练的家伙吧,看不到三行它就把你引向View了,那就看看View吧。
View里有对应的子类负责相应功能的显示。就是从Model获取的数据后塞到HTML中。之所以UI方面写得如此简陋,是因为这些工作可以交给Smarty这样的模板去做,而我们这里就像集中精力研究MVC,不想把Smarty扯进来,所以就这样凑合了,以后我们可以再把Smarty结合进来。
我也是个初学者,这是个依葫芦画瓢之作,目的就是想了解一下MVC,如果你是高手,我很想得到你的点评,这样的划分和架构是否符合MVC的理念?还有哪些应该改进之处?
当然,大家都知道现在很多关于MVC的争论,这很正常,就像关于开发语言的争论一样,永无休止,学术上的争论有助于创新。作为我们学技术、用技术而言,一定要踏实深入学习,掌握了基本用法之后再去讨论,那才是更高层次的发展,在自己都搞不清的情况下在哪里争论只能是浪费时间。
下面说说我体会到的MVC的好处,它的确给程序的功能扩展带来方便,比如这个例子我们想要增加一个根据用户名查询留言的功能,只需要在Model里增加一个查询函数(突然发现这些函数的用法很像存储过程),Controller和View里增加相应的子类,这种分离带来的好处是程序功能模块可以即插即用,再就是整个程序的逻辑非常清晰。我想,对于需求变动频繁的Web应用来说,这种特性也许是很有价值的。


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() { echo($this->output);} //输出最终格式化的HTML数据
}
class listView extends View //显示所有留言的子类
{
function __construct(&$model)
{
parent::__construct(&$model); //继承父类的构造函数(详见Controller)
$this->model->listNote();
while ($note=$this->model->getNote()) //逐行获取数据
{
$this->output.="姓名:$note[name]<br> 留言:<br> $note[content]
<a href=\"".$_SERVER['PHP_SELF']."?action=delete&id=$note[id]\">删除</a><br> <hr />";
}
}
}
class postView extends View //发表留言的子类
{
function __construct(&$model, $post)
{
parent::__construct(&$model);
$this->model->postNote($post[name],$post[content]);
$this->output="Note Post OK!<br><a href=\"".$_SERVER['PHP_SELF']."?action=list\">查看</a>";
}
}
class deleteView extends View //删除留言的子类
{
function __construct(&$model, $id)
{
parent::__construct(&$model);
$this->model->deleteNote($id);
$this->output="Note Delete OK!<br><a href=\"".$_SERVER['PHP_SELF']."?action=list\">查看</a>";
}
}
?>

没有评论:

发表评论