php MVC 及例子解释
根据http://www.21ds.net/article/4/453改写: MVC模式在网站架构中十分常见。它允许我们建立一个三层结构的应用程式,从代码中分离出有用的层,帮助设计师和开发者协同工作以及提高我们维护和扩展既有程式的能力。 视图(View) “视图”主要指我们送到Web浏览器的最终结果——比如我们的脚本生成的HTML。当说到视图时,很多人想到的是模版,但是把模板方案叫做视图的正确性是值得怀疑的。 对视图来说,最重要的事情可能是它应该是“自我意识(self aware)”的,视图被渲染(render)时,视图的元素能意识到自己在更大框架中的角色。 以XML为例,可以说XML在被解析时,DOM API有着这样的认知——一个DOM树里的节点知道它在哪里和它包含了什么。 (当一个XML文档中的节点用SAX解析时只有当解析到该节点时它才有意义。) 绝大多数模板方案使用简单的过程语言和这样的模板标签: <p>{some_text}</p> <p>{some_more_text}</p> 它们在文档中没有意义,它们代表的意义只是PHP将用其他的东西来替换它。 如果你同意这种对视图的松散描述,你也就会同意绝大多数模板方案并没有有效的分离视图和模型。模板标签将被替换成什么存放在模型中。 在你实现视图时问自己几个问题:“全体视图的替换容易吗?”“实现一个新视图要多久?” “能很容易的替换视图的描述语言吗?(比如在同一个视图中用SOAP文档替换HTML文档)” 模型(Model) 模型代表了程序逻辑。(在企业级程序中经常称为业务层(business layer)) 总的来说,模型的任务是把原有数据转换成包含某些意义的数据,这些数据将被视图所显示。通常,模型将封装数据查询,可能通过一些抽象数据类(数据访问层)来实现查询。 举例说,你希望计算英国年度降雨量(只是为了给你自己找个好点的度假地),模型将接收十年中每天的降雨量,计算出平均值,再传递给视图。 控制器(controller) 简单的说控制器是Web应用中进入的HTTP请求最先调用的一部分。它检查收到的请求,比如一些GET变量,做出合适的反馈。在写出你的第一个控制器之前,你很难开始编写其他的PHP代码。 最常见的用法是index.php中像switch语句的结构: <?php switch ($_GET['viewpage']) { case "news": $page=new NewsRenderer; break; case "links": $page=new LinksRenderer; break; default: $page=new HomePageRenderer; break; } $page->display(); ?> 这段代码混用了面向过程和对象的代码,但是对于小的站点来说,这通常是最好的选择。虽然上边的代码还可以优化。 控制器实际上是用来触发模型的数据和视图元素之间的绑定的控件。 q数据库: # Database : `test` # -------------------------------------------------------- # # Table structure for table `products` # CREATE TABLE products ( PRODUCTID int(11) NOT NULL auto_increment, PRODUCTNAME varchar(255) NOT NULL default '', UNITPRICE varchar(255) NOT NULL default '', UNITSINSTOCK varchar(255) NOT NULL default '', DISCONTINUED varchar(255) NOT NULL default '', PRIMARY KEY (PRODUCTID) ) TYPE=MyISAM; # # Dumping data for table `products` # INSERT INTO products VALUES (1, 'Chai', '18', '39', '0'); INSERT INTO products VALUES (2, 'Chang', '19', '17', '0'); INSERT INTO products VALUES (3, 'Aniseed Syrup', '10', '13', '0'); INSERT INTO products VALUES (4, 'Chef Antons Cajun Seasoning', '22', '53', '0'); INSERT INTO products VALUES (5, 'Chef Anton Gumbo Mix', '21.35', '0', '1'); 例子 这里是一个使用MVC模式的简单例子。 首先我们需要一个数据库访问类,它是一个普通类。 lib/DataAccess.php <?php /** *数据库连接和查询 *$db 数据库连接标识符 *$query 获取数据资源标识符 */ class DataAccess { public $db; public $query; // 构造函数 function __construct($host, $user, $password, $dbname){ $this->db = mysql_connect($host, $user, $password); mysql_select_db($dbname, $this->db); mysql_query("set names utf8"); } // 获取数据资源标识符 function fetch($sql){ $this->query=mysql_query($sql, $this->db); } // 获取数据集 function getRow(){ if($row = mysql_fetch_array($this->query, MYSQL_ASSOC)) return $row; else return false; } } ?> 在它上边放上模型。 lib/ProductModel.php <?php /** * 数据模型(model) * $dao DataAccess 的一个对象 */ class ProductModel { public $dao; // 构造函数 function __construct(&$dao){ $this->dao = & $dao; } // 查询多条数据,并把资源标识符保存在 DataAccess 数据对象的 query 中 function listProducts($start=0, $rows=50){ // 调用 DataAccess 对象的 fetch() 方法,获取并保存资源标识符 $this->dao->fetch("select * from products limit " . $start.", ".$rows); } // 查询单条数据,并把资源标识符保存在 DataAccess 数据对象的 query 中 function listproduct($id){ // 调用 DataAccess 对象的 fetch() 方法,获取并保存资源标识符 $this->dao->fetch("select * from products where productid='" . $id."'" ); } // 从 DataAccess 对象 的资源标识符中获取数据集 function getProduct(){ // 调用 DataAccess 对象的 getRow() 方法,获取数据集 if($product = $this->dao->getRow()) return $product; else return false; } } ?> 接下来是视图 lib/ProductView.php <?php /** * 数据视图(view) * $model ProductModel 一个对象 * $output 输出的字符串 */ class ProductView { public $model; public $output; // 构造函数 function __construct(&$model){ $this->model = &$model; } // 头部内容 function header(){ $this->output="<a href=\"".$_SERVER['PHP_SELF']."\">Start Over</a>"; } // 底部内容 function footer(){ $this->output.=""; } // 获取单条详细的数据信息 function productItem($id=1){ // 调用 ProductModel 对象的 listProduct()方法来调用DataAccess 对象的 fetch() 方法,获取并保存资源标识符 $this->model->listProduct($id); // 调用ProductModel 对象中的 getProduct() 方法来调用DataAccess 对象的 getRow() 方法,从标识符中读取数据集 while($product=$this->model->getProduct()){ $this->output.=$product['PRODUCTID'].' ==> ' . $product['PRODUCTNAME']. $product['UNITPRICE']. $product['UNITSINSTOCK']; if($this->product['DISCONTINUED'] == 1){ $this->output.="This product has been discontinued."; } } } // 获取多条数据集合 function productTable($rownum=0){ $rowsperpage = 20; // 调用 ProductModel 对象的 listProduct()方法来调用DataAccess 对象的 fetch() 方法,获取并保存资源标识符 $this->model->listProducts($rownum, $rowsperpage); // 调用ProductModel 对象中的 getProduct() 方法来调用DataAccess 对象的 getRow() 方法,从标识符中读取数据集 while($product = $this->model->getProduct()){ $this->output.="<a href=\"".$_SERVER['PHP_SELF']."?view=product&id=".$product['PRODUCTID']."\">". $product['PRODUCTID'] . ' ==> ' . $product['PRODUCTNAME']."</a>". $product['UNITPRICE']; } if($rownum > 0){ $this->output.="<a href=\"".$_SERVER['PHP_SELF']."?view=table&rownum=".($rownum-$rowsperpage). "\"><< Prev </a>"; } if($product['PRODUCTID'] < ($rownum+$rowsperpage)){ $this->output.="<a href=\"".$_SERVER['PHP_SELF']."?view=table&rownum=".($rownum+$rowsperpage). "\">Next >></a>"; } } // 显示字符串 function display(){ return $this->output; } }?> 最后是控制器,我们将把视图实现为一个子类。 lib/ProductController.php <?php /** * 控制器(controller) * 通过继承 ProductView 类 * $model 是 ProductModel 的一个对象实例 * $getvars 是一个 $_GET 的参数数组 * index.php?view=product&id=5 * index.php?view=table&rownum=20 */ class ProductController extends ProductView { function __construct(&$model, $getvars = null){ parent::__construct(&$model); switch($getvars['view']){ case "product": // 调用 ProductView 对象中的 productItem()方法来显示数据 $this->productItem($getvars['id']); break; default: // 调用 ProductView 对象中的 productItem()方法来显示数据 if(empty($getvars['rownum'])){ $this->ProductTable(); }else{ $this->productTable($getvars['rownum']); } break; } } } ?> 最后是调用的首页 index.php <?php require_once('lib/DataAccess.php'); require_once('lib/ProductModel.php'); require_once('lib/ProductView.php'); require_once('lib/ProductController.php'); $dao =& new DataAccess('localhost', 'root', '123456', 'test'); $productModel = &new ProductModel($dao); $productController = & new ProductController($productModel, $_GET); echo $productController->display(); ?>