首页 php教程 php手册 php之mvc框架演进过程详解

php之mvc框架演进过程详解

Jun 13, 2016 am 10:57 AM
html mvc php 功能 完成 思路 框架 混编 演进 设计 详解 过程

1)  /********** php与html混编完成增删改查功能**************************/

1.设计思路:

   根据平时练习一个增删改查的功能进行,即在一个php文件中完成,对数据库的连接操作

   及在php文件中展示html代码。html提交到当前页面的php部分进行处理入库动作。

  

  $_SERVER['SCRIPT_FILENAME']包含当前脚本的路径。

      这在页面需要指向自己时非常有用。

      区别于__FILE__常量包含当前脚本(例如包含文件)的完整路径和文件名。

 

第一个类:增加商品文件:addProduct.php

 

if(isset($_POST['submit'])){

   $name= $_POST['name'];

   $price= $_POST['price'];

   $description= $_POST['description'];

  

   //连接数据库操作

   mysql_connect('localhost','root','master');

   mysql_select_db('test');

   mysql_query('set names gbk');

  

   $query= "insert into product values(null,'$name','$price','$description')";

  

   mysql_query($query);

  

   mysql_close();

}

 

?>

 

'>

   产品名称

   产品价格

   产品描述

  

  

 

 

思路:都是在同一文件(当前文件中)操作数据库和展示:

Mysql_fetch_assoc 返回数组,一般需要放到一个空数组内组成一个二维数组返回到页面 mysql_num_rows返回行数

 

查询数据一般常用:

Php中

$result = Mysql_query(“select * fromproduct order by id desc”);

$data = array();

While ($row = Mysql_fecth_assoc($result)){

         $data[]= $row;

}

Html中:

 

                 

             ……

 

查询商品文件: listProduct.php

 

//连接数据库操作

mysql_connect('localhost','root','master');

mysql_select_db('test');

mysql_query('set names gbk');

 

$query = "select * from product order by id desc";

 

$result = mysql_query($query);

 

$data = array();

while($row = mysql_fetch_assoc($result)){

   $data[]= $row;

}

 

?>

 

  

     

编号

     

名称

     

价格

     

描述

     

删除

     

更新

  

  

      foreach($dataas$row):

   ?>

  

     

     

     

     

     

">删除

     

">更新

  

  

 

 

 

 

 

 

思路:接下来就进行删除和更新操作,同样是请求到新的php一个文件中来处理删除和更新操作。新建php文件:delProduct.php

delProduct.php:

 

//连接数据库操作

mysql_connect('localhost','root','master');

mysql_select_db('test');

mysql_query('set names gbk');

$id = $_GET['id'];

 

$query = "delete from product where id = '$id'";

 

mysql_query($query);

 

mysql_close();

 

//同时跳到listProduct展示结果

header('location:listProduct.php');

 

 

更新操作:

updateProduct.php(以下类只是作为展示,提交修改还需要一个php文件,为了不再增加一个文件,修改提到本页面,在action中增加一个参数区别展示和提交修改的操作)

 

//连接数据库操作

mysql_connect('localhost','root','master');

mysql_select_db('test');

mysql_query('set names gbk');

 

 

$id = $_GET['id'];

 

$query = "select * from product where id = '$id'";

 

$result = mysql_query($query);

 

$row = mysql_fetch_row($result);

 

?>

 

   "/>

   产品名称"/>

   产品价格"/>

   产品描述"/>

  

  

 

 

修后类内容如下:

 

 

//连接数据库操作

mysql_connect('localhost','root','master');

mysql_select_db('test');

mysql_query('set names gbk');

 

if(isset($_REQUEST['flag'])){

   $id= $_POST['id'];

   $name= $_POST['name'];

   $price= $_POST['price'];

   $description= $_POST['description'];

  

   $query= "update product set name = '$name', price = '$price' , description = '$description' where id='$id'";

  

   mysql_query($query);

  

   mysql_close();

  

   header('location:listProduct.php');

  

}else{

   $id= $_GET['id'];

  

   $query= "select * from product where id = '$id'";

  

   $result= mysql_query($query);

  

   $row= mysql_fetch_row($result);

}

 

?>

 

   "/>

   产品名称"/>

   产品价格"/>

   产品描述"/>

  

  

 

 

 

/**************加入DB类封装对数据库的操作***************/

此时,已经完成了商品的增删改查基本功能了,但是,有很多的冗余代码,比如数据库的操作,这时可以考虑把数据的操作提取出来:

 

DB.class.php:

/**

 * 数据库操作类

 * @author heyongjia

 *

 */

class DB{

  

   private$host ='localhost';

   private$username ='root';

   private$password ='master';

   private$dbname ='test';

   private$setCoding ='set names gbk';//注意编码的设置,有时候会出现插入不成功的情况

  

   private$conn;//连接资源

   private$result;//结果集

 

  

   public functionconnect(){

      $this->conn =mysql_connect($this->host,$this->username,$this->password);

      mysql_select_db($this->dbname);

      mysql_query($this->setCoding);

   }

  

   public functionquery($query){

      $this->result = mysql_query($query);

   }

  

   public functionclose(){

      mysql_close();

   }

}

 

 

 

然后分别改造addProduct.php、delProduct.php、listProduct.php、updateProduct.php操作数据库部分,把每个文件中连接数据,查询的部分提取到数DB.class.php中,修改之后如下:

addProduct.php

if(isset($_POST['submit'])){

   $name= $_POST['name'];

   $price= $_POST['price'];

   $description= $_POST['description'];

  

 

   $query= "insert into product values(null,'$name','$price','$description')";

   $db =newDB();

   $db->connect();

   $db->query($query);

   $db->close();

}

 

 

delProduct.php:

 

include 'class/DB.class.php';

 

$id = $_GET['id'];

 

$query = "delete from product where id = '$id'";

 

$db = newDB();

$db->connect();

$db->query($query);

$db->close();

 

//同时跳到listProduct展示结果

header('location:listProduct.php');

 

 

 

listProduct.php:

 

//连接数据库操作

include 'class/DB.class.php';

 

$query = "select * from product order by id desc";

 

$db = newDB();

$db->connect();

$db->query($query);

$data = array();

while($row = $db->fetch_assoc()){

   $data[]= $row;

}

$db->close();

 

?>

 

/***********引用product对象进行数据传递,即数据模型*********************/

思路:增删改查的操作属于业务逻辑,应该封装起来。

封装到类Product.class.php

 

class Product {

  

   private$id;

   private$name;

   private$price;

   private$description;

  

   public function__set($name,$value){

      $this->$name= $value;

   }

  

   public function__get($name){

      return$this->$name;

   }

  

   public functionadd(){

      $query= "insert into product values(null,'$this->name','$this->price','$this->description')";

      $db= newDB();

      $db->connect();

      $db->query($query);

      $db->close();

   }

}

 

 

然后在addProduct.php中引入该类,并修改操作数据库动作:

   $product= newProduct();

   $product->name = $name;

   $product->price = $price;

   $product->description = $description;

   $product->add();

 

 

其它的操作数据库方法类似。

 

 

 

思路:通过观察addProduct.php、delProduct.php、listProduct.php、updateProduct.php都有类似的代码,那么可不可以整合在一起呢,完成所有模块的相关请求。

 

新建一个product.php文件,addProduct.php、delProduct.php中的相关操作数据库的代码拷贝到product.php文件中,并且在product.php中以action参数来区分不同的请求。

 

 

//用于完成所有相关product操作的请求

include 'class/DB.class.php';

include 'class/Product.class.php';

 

 

$action = $_GET['action'];

 

if($action =='add'){

   //增加

   $name= $_POST['name'];

   $price= $_POST['price'];

   $description= $_POST['description'];

  

   $product= newProduct();

   $product->name = $name;

   $product->price = $price;

   $product->description = $description;

   $product->add();

}

 

if($action =='del'){

   //删除

   $id= $_GET['id'];

  

   $product= newProduct();

   $product->id = $id;

   $product->del();

  

   //同时跳到listProduct展示结果

   header('location:listProduct.php');

}

 

 

 

这时可以把addProduct.php中的php代码部分删除了,并把html部分独立出来一个addProduct.html文件,

同时也可以把delProduct.php文件删除,因为这两个php文件的php代码都移动了product.php中了。

 

/********************加入Smarty模拟类库******************************/

先把以上两个功能先完成,

1.       访问addProduct.html文件,完成增加操作,并跳转回addProduct.html页面。访问listProduct.php文件,查看增加的结果。

 

2.       访问listProduct.php文件,并修改删除链接的请求指向。并同时完成删除的功能。

 

此时product.php的代码如下:

 

 

//用于完成所有相关product操作的请求

include 'class/DB.class.php';

include 'class/Product.class.php';

 

 

$action = $_GET['action'];

 

if($action =='add'){

   //增加

   $name= $_POST['name'];

   $price= $_POST['price'];

   $description= $_POST['description'];

  

   $product= newProduct();

   $product->name = $name;

   $product->price = $price;

   $product->description = $description;

   $product->add();

  

   header('location:addProduct.html');

}

 

if($action =='del'){

   //删除

   $id= $_GET['id'];

  

   $product= newProduct();

   $product->id = $id;

   $product->del();

  

   //同时跳到listProduct展示结果

   header('location:listProduct.php');

}

 

/**************加入smarty类库************************/

思路:此时已经把增加和删除功能已经集合到了product.php中了,还有查询和更新操作,由于listProduct.php中包含了显示数据列表的功能,不容易展示(可以采用include一个页来完成。)。此时,可以用smarty来完成,这样就合理了。

 

这时可以考虑把addProduct.html也放入product.php来展示,修改成:

include 'class/Template.class.php';//注意导入该文件,该文件是模拟smarty实一类文件。(考虑到查询功能也用要到,需要展示多个数据,所以模拟Smarty的类文件无法胜任,就直接引入smarty来作为展示)

 

 

/***********************加入smarty类库********************/

这时可以把自己的写的Templates类继承Smarty类,这样就可以使用Smarty中的功能,还可以扩展其功能。

 

Template.class.php内容如下:

 

/**

 * 继承了Smarty类的Template类

 * @author heyongjia

 *

 */

 

class TemplateextendsSmarty{

   /**

    * 调用父类的构造方法,确保父类中的构造方法已经执行

    * 因为子类如果有构造方法,就不会执行父类中的构造方法

    */

   function__construct(){

      parent::__construct();

      //初始化模板目录

      $this->setTemplateDir('tpl');

   }

  

}

 

 

 

至此,CRUD功能已经整合在一product.php文件中了,也说是所有的请求都经过它,如:

Localhost/test/mvc/product.php?action=add/list/update等请求。这时product.php就相当于一个控制器的角色了。

 

 

/****************  加入入口文件  *******************************、

 

我们程序中,会有很多的控制器,为了便于管理,我们定义一个入口文件,也就是说,所有的请求都经过这个入口文件,再由这个入口进行分发到各个控制器。

 

增一个index.php文件:

用于分发到控制器:

请求的url:

Localhost/test/mvc/index.php?module=product&action=add/list/update

 

所以index.php文件如下:

 

$module = $_GET['module'];

$action = $_GET['action'];

 

$file = $module.'Control.php?action='.$action;

 

header('location:'.$file);

 

 

此时,就可以通过上面的入口文件分发到不同的控制器(模块)上的不同的操作(功能),但是由于使用的是header跳转,在浏览器上地址栏就变成了跳转后的地址了,即脱离了入口文件。

 

那么,如何实现?

 

将product.php改成一个类来实现。改造product.php为ProductControl.class.php,并移动control文件夹下,内容如下:

 

class ProductControl{

  

   public functionaddok(){

      //增加

      $name= $_POST['name'];

      $price= $_POST['price'];

      $description= $_POST['description'];

     

      $product= newProduct();

      $product->name = $name;

      $product->price = $price;

      $product->description = $description;

      $product->add();

     

      header('location:product.php?action=list');

   }

  

   public functionadd(){

      $smarty= newTemplate();

      //$tpl = new Template();

      //$tpl->display('addProduct.html');

      $smarty->display('addProduct.html');

   }

  

   public functiondel(){

      //删除

      $id= $_GET['id'];

     

      $product= newProduct();

      $product->id = $id;

      $product->del();

     

      //同时跳到listProduct展示结果

      header('location:product.php?action=list');

   }

  

   public functionupdate(){

      $smarty= newTemplate();

      $id= $_GET['id'];

     

      $product= newProduct();

      $product->id = $id;

      $row= $product->getRow();

      $smarty->assign('id',$row['id']);

      $smarty->assign('name',$row['name']);

      $smarty->assign('price',$row['price']);

      $smarty->assign('description',$row['description']);

      $smarty->display('updateProduct.html');

   }

  

   public functionupdateok(){

      $id= $_POST['id'];

      $name= $_POST['name'];

      $price= $_POST['price'];

      $description= $_POST['description'];

     

     

      $product= newProduct();

      $product->id = $id;

      $product->name = $name;

      $product->price = $price;

      $product->description = $description;

     

      $product->update();

     

      header('location:product.php?action=list');

   }

 

}

 

此时,如何调用这个类的方法呢?在index.php中实例化该对象调用。

 

//用于完成所有相关product操作的请求

include 'class/DB.class.php';

include 'class/Product.class.php';

include 'smarty/Smarty.class.php';

include 'class/Template.class.php';

 

$module = $_GET['module'];

$module = ucfirst($module);

$action = $_GET['action'];

 

$className = $module.'Control';

 

include 'control/'.$className.'.class.php';

 

$class = new$className; //根据模块名引用类文件并实例化该对象

 

$class->$action(); //调用对应的action方法。

 

 

修改调用的所有路径为:index.php?module=product&action=xxx

addProduct.html updateProduct.htmllistProduct.html

 

 

优化:一般地不会在index.php文件中写太多的代码,可以将代码移动配置文件中,在index.php中引入即可。

 

 

一般地,整个工程会有一个主控制器类,用于处理分发控制器,Application.class.php:

 

 

class Application{

  

   static functionrun(){

      global$module; //函数内要使用外部的变量

      global$action;

      $className= $module.'Control';

     

      include'control/'.$className.'.class.php';

     

      $class= new$className;

     

      $class->$action();

   }

}

 

 

init.php:

 

//用于完成所有相关product操作的请求

include 'class/DB.class.php';

include 'class/Product.class.php';

include 'smarty/Smarty.class.php';

include 'class/Template.class.php';

include 'control/Application.class.php';

 

$module = $_GET['module'];

$module = ucfirst($module);

$action = $_GET['action'];

 

 

 

Index.php:

 

 

include 'config/init.php';

Application::run();

 

 

 

此时,访问的url为: index.php?module=product&action=xxx

 

但如果直接访问index.php就会报错:


Notice: Undefined index: module in F:\amp\apache\studydocs\test\php_js\mvc\config\init.phpon line10

Notice: Undefined index: action in F:\amp\apache\studydocs\test\php_js\mvc\config\init.phpon line12

 

这是因为在init.php中没有对module和action进行初始化。

并将值配置到config文件夹下的conig.php文件中。

 

 

 

由于在product.php文件中(其实就是模型类),有很多类似的操作数据库的代码,所以可以将这部分代码封装到父类实现,该模型类只需要继承即可。

 

/******************封装核心文件core**************************

新建一个文件夹core,将DB.class.php和Application.php移动到core因为是共公的文件,不属于功能文件。

 

新建一个基类文件(模型基类),用于实现对数据库实例化的封装,而子类模型只需要继承即可获取数据库对象的实例。

 

Model.class.php:

 

class Medel{

  

   protected$db;

  

   public function__construct(){

      $this->db =newDB();

   }

}

 

 

新建文件夹model,然后将product.php移动到model文件夹下,并改名ProductModel.class.php:

 

class ProductModelextendsModel {

  

   private$id;

   private$name;

   private$price;

   private$description;

  

   public function__set($name,$value){

      $this->$name= $value;

   }

  

   public function__get($name){

      return$this->$name;

   }

  

   public functionadd(){

      $query= "insert into product values(null,'$this->name','$this->price','$this->description')";

      $this->db->connect();

      $this->db->query($query);

      $this->db->close();

   }

  

   public functiondel(){

      $query= "delete from product where id = '$this->id'";   

      $this->db->connect();

      $this->db->query($query);

      $this->db->close();

   }

  

   public functionselect(){

      $query= "select * from product order by iddesc";     

      $this->db->connect();

      $this->db->query($query);

      $data= array();

      while($row = $this->db->fetch_assoc()){

         $data[]= $row;

      }

      $this->db->close();

      return$data;

   }

  

   public functionupdate(){

      $query= "update product set name = '$this->name', price = '$this->price' , description = '$this->description' where id='$this->id'";

      $this->db->connect();

      $this->db->query($query);

      $this->db->close();

   }

  

   public functiongetRow(){

     

      $query= "select * from product where id = '$this->id'";

     

      $this->db->connect();

      $this->db->query($query);

      $row= $this->db->fetch_assoc();

      $this->db->close();

      return$row;

   }

  

  

}

 

/***********************视图封装**************************

在控制器中每次都要实例化Template类,并调用display方法。

 

把Template.class.php移动core文件夹中,并改名为View.class.php:

 

这么做的好处,让每一个控制继承于该类(构造一个控制器基类Control.class.php,在类中构造一个视图实例),只要每个控制器继承了该类(Control.class.php),即拥有了smarty实例。

 


/**

 * 1.继承了Smarty类的Template类

 * 2.不用继承Smarty了,是smarty的一个实例

 * @author heyongjia

 *

 */

 

class Viewextends Smarty{

  

  

}

这么做的好处,让每一个控制继承于该类(构造一个控制器基类Control.class.php,在类中构造一个视图实例),只要每个控制器继承了该类(Control.class.php),即拥有了smarty实例。

 

/**

 * 控制器基类

 * @author heyongjia

 *

 */

class Controlextends View{

   protected$view;

  

   public function__construct(){

      $this->view = new View();

$this->view->setTemplateDir('tpl');

   }

  

}


 

优化,直接在init.php中直接包含模型是不对的,因为可以出现很多的模型。这时可以考虑自动加载机载来实现。注意:smarty3.0中也用到了自动加载函数,所以要利用注册来完成。

 

function autoload1($classname){

   $filename= 'model/'.$classname.'.class.php';

   if(is_file($filename)){

      include"$filename";

   }

}

 

spl_autoload_register('autoload1');

 

function addslashes_func(&$str){

   $str= addslashes($str);

}

 

if(!get_magic_quotes_gpc()){

   array_walk_recursive($_POST,'addslashes_func');

   array_walk_recursive($_GET,'addslashes_func');

}

 

此至,就mvc简易框架就到这里差不多了。

 


用图总结一下,这样就比较直观了:

 

 

 

 

 

 

 

 

 

 


 


 

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 适用于 Ubuntu 和 Debian 的 PHP 8.4 安装和升级指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

CakePHP 文件上传 CakePHP 文件上传 Sep 10, 2024 pm 05:27 PM

为了进行文件上传,我们将使用表单助手。这是文件上传的示例。

讨论 CakePHP 讨论 CakePHP Sep 10, 2024 pm 05:28 PM

CakePHP 是 PHP 的开源框架。它的目的是使应用程序的开发、部署和维护变得更加容易。 CakePHP 基于类似 MVC 的架构,功能强大且易于掌握。模型、视图和控制器 gu

如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 如何设置 Visual Studio Code (VS Code) 进行 PHP 开发 Dec 20, 2024 am 11:31 AM

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

CakePHP 快速指南 CakePHP 快速指南 Sep 10, 2024 pm 05:27 PM

CakePHP 是一个开源MVC 框架。它使开发、部署和维护应用程序变得更加容易。 CakePHP 有许多库可以减少大多数常见任务的过载。

您如何在PHP中解析和处理HTML/XML? 您如何在PHP中解析和处理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示了如何使用PHP有效地处理XML文档。 XML(可扩展的标记语言)是一种用于人类可读性和机器解析的多功能文本标记语言。它通常用于数据存储

php程序在字符串中计数元音 php程序在字符串中计数元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符组成的序列,包括字母、数字和符号。本教程将学习如何使用不同的方法在PHP中计算给定字符串中元音的数量。英语中的元音是a、e、i、o、u,它们可以是大写或小写。 什么是元音? 元音是代表特定语音的字母字符。英语中共有五个元音,包括大写和小写: a, e, i, o, u 示例 1 输入:字符串 = "Tutorialspoint" 输出:6 解释 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。总共有 6 个元

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

See all articles