Chinaunix首页 | 论坛 | 博客
  • 博客访问: 198491
  • 博文数量: 264
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 2740
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-03 13:25
文章分类

全部博文(264)

文章存档

2011年(1)

2009年(263)

我的朋友

分类:

2009-06-03 17:41:16

经过一番搜索,找到了一篇翻译文章(作者:Harry Fuecks 翻译:Easy Chen URL:  原文URL:)作者以商品目录浏览为例,给出了完整的MVC架构代码。仔细一看,发现他的C和V是继承关系,耦合很紧,似乎不是很理想,但马上又看到了作者的第二个版本(),这个版本的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是一个简单的数据库访问类。


/**

 *  一个用来访问MySQL的类

 *  仅仅实现演示所需的基本功能,没有容错等

 *  代码未作修改,只是把注释翻译一下,加了点自己的体会

 */

class DataAccess {

    

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

   

    
var $query_id//用于存储查询

    //! 构造函数.

    /**

    * 创建一个新的DataAccess对象

    * @param $host 数据库服务器名称

    * @param $user 数据库服务器用户名

    * @param $pass 密码

    * @param $db   数据库名称

    */

    
function __construct($host,$user,$pass,$db) {

        
$this->link_id=mysql_pconnect($host,$user,$pass); //连接数据库服务器

        
mysql_select_db($db,$this->link_id);              //选择所需数据库

                                              

  
mysql_query("set names utf8;");

    }

    
//! 执行SQL语句

    /**

    * 执行SQL语句,获取一个查询源并存储在数据成员$query中

    * @param $sql  被执行的SQL语句字符串

    * @return void

    */

    
function query($sql) {

        
$this->query_id=mysql_unbuffered_query($sql,$this->link_id); // Perform query here

        
if ($this->query_id) return true;

  else return 
false;

 }

    
//! 获取结果集

    /**

    * 以数组形式返回查询结果的所有记录

    * @return mixed

    */

    
function fetchRows($sql) {

        
$this->query($sql);

  
$arr=array();

  
$i=0;

  while( 
$row=mysql_fetch_array($this->query_id,MYSQL_ASSOC) )

                                             
//MYSQL_ASSOC参数决定了数组键名用字段名表示

  
{   $arr[$i]=$row;

      
$i++;

   }

            return 
$arr;

       

    }

}

?>

复制代码
下面再来介绍一下Model类。
    这个类也很简单,里面的函数一看就知道,是针对各种数据操作的,它通过DataAccess访问数据库。


 

 
//! 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() {    //获取全部留言

        
$notes=$this->dao->fetchRows("SELECT * FROM note ORDER BY timedate DESC");

  

            return 
$notes;

         

    }

 

 function 
postNote() {    //插入一条新留言

     

  
$name=$_POST['username'];

        
$email=$_POST['email'];

        
$content=$_POST['content'];

        
$timedate=time()+8*3600;

  
$sql="INSERT INTO note (name, email, content, timedate) VALUES 

             ('"
.$name."', '".$email."', '".$content."', '".$timedate."' )";

     
//echo $sql;  //对于较复杂的合成SQL语句,

                      //调试时用echo输出一下看看是否正确是一种常用的调试技巧

  
if ($this->dao->query($sql)) return true;

  else return 
false;

 }

 

 function 
deleteNote() {   //删除一条留言,$id是该条留言的id

     
$sql="DELETE FROM note WHERE id=".$_GET['id'];

  if (
$this->dao->query($sql)) return true;

  else return 
false;

 }

 

  

}

?>

复制代码
看完这两个类之后你可能会发现这与以前我们写程序差不多,的确现在还闻不到MVC的味道,如果你不懂MVC,在这两个类的基础上你完全可以开始写你以前的程序了。例如要显示全部留言,只需要写入下代码:


require_once('lib/DataAccess.php');

require_once(
'lib/Model.php');



$dao=& new DataAccess ('localhost','root','password','test');

$model=& new Model($dao);

$notes=$model->listNote();

……

?>


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


 
//! 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);  //继承其父类的构造函数

                               //该行的含义可以简单理解为:

          //将其父类的构造函数代码复制过来

      
$notes=$this->model->listNote();

   
$this->view=& new listView($notes);

                               
//创建相应的View子类的对象来完成显示

         

 

 

 
}

}

//用于控制添加留言的子类

class postController extends Controller{

 function 
__construct (& $dao) {

      
parent::__construct($dao);

   if (
$this->model->postNote()) $success=1;

   else 
$success=0;

   
$this->view=& new postView($success);

 }

}

//用于控制删除留言的子类

class deleteController extends Controller{

 function 
__construct (& $dao) {

      
parent::__construct($dao);

      if (
$this->model->deleteNote()) $success=1;

   else 
$success=0;

   
$this->view=& new deleteView($success);

 }

}



?>

复制代码
大体浏览之后,你一定打算开始仔细研究它了吧,别急,为了心中有数,我们先从宏观着眼,先看看总入口index.php是如何调用Controller的:
<html>

<
head>

<
meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<
title>PHP MVC留言板title>

head>

<
body leftmargin="50px">

<
a href="notebook.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','your password here','notebook');

//根据$_GET["action"]取值的不同调用不同的控制器子类

$action=$_GET["action"];

switch (
$action)

{

   case 
"post":

      
$controller=& new postController($dao); break;

   case 
"list":

      
$controller=& new listController($dao); break;

   case 
"delete":

      
$controller=& new deleteController($dao); 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的原因,它所做的 就是把Controller(Controller是个二道贩子,它的数据来自Model)给它的数据,然后塞到HTML中。


//! View 类

 /**

 * 针对各个功能(list、post、delete)的各种View子类

 * 被Controller调用,完成不同功能的网页显示

 */

class View {

   

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

 

 
function display() {  //输出最终格式化的HTML数据

     
echo($this->output);

   

 }

}

class 
listView extends View   //显示所有留言的子类

{

    function 
__construct($notes)

 {

   foreach (
$notes as $value)

   {

      
$this->output.="

访客姓名:".$value['name']."

"
.

                     
"

访客邮箱:".$value['email']."

"
.

                     
"

访客留言:".$value['content']."

"
.

                     
"

来访时间:".date("y-m-d H:i",$value['timedate'])."

"
.

      
".$value['id']."\">删除留言".

                        
"";    

   }

   

   

 }

}

class 
postView extends View  //发表留言的子类

{

    function 
__construct($success)

 {

    if (
$success)

    
$this->output="留言成功!
.$_SERVER['PHP_SELF']."?action=list\">查看";

    else

    
$this->output="留言保存失败!";

 }

}

class 
deleteView extends View  //删除留言的子类

{

    function 
__construct($success)

 {

    if (
$success)

    
$this->output="留言删除成功!
.$_SERVER['PHP_SELF']."?action=list\">查看";

   

 }

}

?>

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

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