`
happmaoo
  • 浏览: 4472106 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

最简单的PHP MVC留言本实例

阅读更多

这个帖子发布以后有朋友指出例子中V直接操作M不符合MVC原则,现在对代码做了修改:
在C中调用M中的方法返回数据(如全部留言数据),将M返回的数据传递给V,这样C操作M和V,V不再直接与M联系。

欢迎大家多多拍砖!

写完那篇“写给懂C语言的人的PHP基本语法入门”后一直在学习PHP5的OOP,目的很简单,就是想研究MVC的PHP实现,所以,兴趣很快转移到MVC上面,网上有很多长篇大论,但是看完了我还是不能写出一个最简单的MVC程序,我这个人学东西有个习惯,那就是先要掌握一个最简单的“Hello World”,然后再以此为基础扩展开去,否则心里没底,一头雾水。
经过一番搜索,找到了一篇翻译文章(作者:Harry Fuecks 翻译:Easy Chen URLhttp://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 $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;

}
}
?>
[/php]
下面再来介绍一下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() { //获取全部留言
$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语句,<br />
//调试时用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;
}


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

$dao=& new DataAccess ('localhost','root','password','test');
$model=& new Model($dao);
$notes=$model->listNote();
……
?>[/php]
很亲切吧,呵呵。
有了这个“感情基础”你就不会对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);//继承其父类的构造函数
//该行的含义可以简单理解为:
//将其父类的构造函数代码复制过来
$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);
}
}

?>

[/php]
大体浏览之后,你一定打算开始仔细研究它了吧,别急,为了心中有数,我们先从宏观着眼,先看看总入口index.php是如何调用Controller的:
[php]
<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
?>
</body>
</html>

[/php]
看过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中。
[php]
<?php
//! 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.="<p><strong>访客姓名:</strong>".$value['name']."</p>".
"<p><strong>访客邮箱:</strong>".$value['email']."</p>".
"<p><strong>访客留言:</strong>".$value['content']."</p>".
"<p><strong>来访时间:</strong>".date("y-m-d H:i",$value['timedate'])."</p>".
"<p align=\"right\"><a href=\"index.php?action=delete&id=".$value['id']."\">删除留言</a>".
"<hr />";
}


}
}
class postView extends View//发表留言的子类
{
function __construct($success)
{
if ($success)
$this->output="留言成功!<br><a href=\"".$_SERVER['PHP_SELF']."?action=list\">查看</a>";
else
$this->output="留言保存失败!";
}
}
class deleteView extends View//删除留言的子类
{
function __construct($success)
{
if ($success)
$this->output="留言删除成功!<br><a href=\"".$_SERVER['PHP_SELF']."?action=list\">查看</a>";

}
}
?>

[/php]

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

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

分享到:
评论

相关推荐

    一个简单的PHP MVC留言本实例

    标题上我把这个留言板叫最简单的,其实应该叫最简陋的,因为把全部注意力集中在MVC模式设计和实现上,所以UI方面几乎没有一点修饰。之所以在这里跟大家分享这个东西,是因为我自己通过读该老外的代码并仿照着写留言...

    最简单的phpMVC实例

    在这个最简单的PHP MVC实例中,我们将探讨如何通过这个小型的留言本应用来理解MVC的运作机制。 【MVC组件解析】 1. **Model(模型)**: 模型层负责处理数据和业务逻辑。在这个例子中,`Model`类代表了与数据库交互...

    最简单的PHP MVC实例

    ### 最简单的PHP MVC实例解析 #### 一、MVC架构简介 MVC(Model-View-Controller)是一种软件架构设计模式,广泛应用于Web应用程序的开发之中。它将应用程序分为三个核心部分: - **Model(模型)**:负责处理应用...

    一个简单的php MVC留言本实例代码(必看篇)

    摘要 标题上我把这个留言板叫最简单的,其实应该叫最简陋的,因为把全部注意力集中在MVC模式设计和实现上,所以UI方面几乎没有一点修饰。 这个小程序一共包含6个文件,其中index.php是程序入口、post.htm是留言表单...

    YAF简单实例你懂的

    在标题 "YAF简单实例你懂的" 中,我们看到这是一个关于 YAF 框架的基本示例教程。通常,这样的实例会涵盖如何创建一个简单的 "Hello, World!" 应用来帮助初学者了解 YAF 的基本使用方法。下面我们将深入探讨 YAF 的...

    PHP实例开发源码—简单留言板.zip

    在本实例中,我们关注的是一个基于PHP的简单留言板系统。这个系统展示了PHP的基本功能以及如何与HTML结合来实现用户交互。PHP(Hypertext Preprocessor)是一种广泛使用的开源脚本语言,尤其适用于Web开发,可以嵌入...

    PHP基于面向对象实现的留言本功能实例

    在本实例中,通过面向对象编程范式(OOP)构建了一个简单的留言本应用。OOP是一种编程方法,它使用对象来代表数据和方法。在这一实践中,主要包含了留言本功能的核心类及其方法,它们是留言实体类、留言本模型类、...

    ThinkPHP项目开发PHP实战_留言板_编程案例解析实例详解课程教程.pdf

    在本课程中,ThinkPHP被用于实现一个简单的留言板项目,以此来教学员如何从零开始开发Web项目。 【ThinkPHP项目开发——留言板系统】 在本课程中,你将学习如何使用ThinkPHP框架开发一个留言板系统。该系统包含了...

    php中用smarty做的留言板

    本示例是使用Smarty构建的一个简单留言板应用,适合初学者学习和理解Smarty的基本用法。 首先,我们需要了解Smarty的核心概念: 1. **模板(Template)**:模板文件通常以`.tpl`为扩展名,里面包含HTML代码和...

    ThinkPHP之用户注册登录留言完整实例

    通过本实例的学习,开发者可以更好地掌握ThinkPHP框架的基本使用方法,并为开发更加复杂的Web应用打下坚实的基础。对于初学者来说,理解了注册、登录以及留言等基础功能的实现过程,将有助于进一步学习ThinkPHP框架...

    thinkphp开发的留言板源代码

    本留言板系统完全基于面向对象的编程思想,这包括类的定义、对象的实例化以及继承、封装和多态等特性。面向对象编程使代码更具有模块化,易于扩展和复用,同时提高了代码的可读性和可维护性。 三、数据的增删改查 ...

    php开发培训最全学习大纲.docx

    【PHP开发培训最全学习大纲】 一、PHP基础详解 1. PHP基本介绍:PHP是一种开源的服务器端脚本语言,主要用于web开发,可以嵌入HTML中,与Apache、Nginx等服务器软件配合使用。 2. Wamp服务器搭建:WAMP是Windows、...

    基于J2EE框架的个人博客系统项目毕业设计论文(源码和论文)

    在web 2.0应用中,博客(Blog)是web 2.0核心应用中最典型、最流行的代表之一,也是web 2.0技术应用的最直观的表现,是web 2.0精神和理念的具体体现。 1.2. 问题的提出 Blog记载了日常发生的事情和自己的兴趣爱好,把...

Global site tag (gtag.js) - Google Analytics