php之mvc设计模式的原理和实现

一、MVC设计模式概述

1.什么是MVC设计模式
2. MVC设计模式的优势和缺点

二、 MVC典型实现

1.模型
   数据库操作类
   模型类
2.控制器
   模块
   控制器类
3.视图
4.前端控制器(入口文件)

一、MVC设计模式概述

1.什么是MVC设计模式

MVC是Xerox PRAC(施乐帕克研究中心)在80年代为编程语言 Smalltalk-80发明的一种软件设计模式,至今已被广泛使用。MVC设计模式强制性的使应用程序中的输入、处理和输出分开,将软件系统分成了三个核心部件:模型(Model)、视图(View)、控制器(Controller) 它们各自处理自己的任务。MVC是一种开发设计规范,使代码组织更加合理、流程更加清晰ThinkPHP框架是基于MVC模式来做为基本运行流程,因此,MVC部分一定要理解掌握,以便于后续的框架学习。

##### 2. MVC设计模式的优势和缺点 1)优点:   各司其职、互不干涉;   有利于开发中的分工;   有利于组建的重用;

2)缺点:
  系统结构和实现复杂;
  视图与控制器过于紧密;
  不适用于小型甚至中型应用程序;

二、 MVC典型实现

  1. 创建模型,生成并返回数据
  2. 创建控制器,将模型和视图整合
  3. 创建视图,展示模型生成并返回的数据
  4. 创建入口文件,调用控制器完成操作

在这里插入图片描述

1.创建模型,生成并返回数据

在面对复杂问题时,面向对象编程可以更好的描述现实中的业务逻辑,所以MVC的程序也是通过面向对象的方式实现的m模型是处理数据的,而数据是存储在数据库里的。在项目中,所有对数据库的直接操作,都应该封装到一个数据库操作类中。
运用学过的面向对象、单例模式、PDO等相关知识,就可以封装一个PDO的数据库操作类。

1)封装一个PDO数据库操作类(Db.php)

<?php
/**
 * PDO-MySQL数据库操作类
 */
class MySQLPDO{
	//数据库默认连接信息
	private $dbConfig = array(
		'db'   => 'mysql', //数据库类型
		'host' => 'localhost', //服务器地址
		'port' => '3306', //端口
		'user' => 'root', //用户名
		'pass' => 'weicunbin123', //密码
		'charset' => 'utf8', //字符集
		'dbname' => 'testguest', //默认数据库
	);
	//单例模式 本类对象引用
	private static $instance;
	//PDO实例
	private $db;
	/**
	 * 私有构造方法
	 * @param $params array 数据库连接信息
	 */
	private function __construct($params){
		//初始化属性
		$this->dbConfig = array_merge($this->dbConfig,$params);
		//连接服务器
		$this->connect();
	}
	/**
	 * 获得单例对象
	 * @param $params array 数据库连接信息
	 * @return object 单例的对象
	 */
	public static function getInstance($params = array()){
		if(!self::$instance instanceof self){
			self::$instance = new self($params);
		}
		return self::$instance; //返回对象
	}
	/**
	 * 私有克隆
	 */
    private function __clone() {}
	/**
	 * 连接目标服务器
	 */
	private function connect(){
		try{
			//连接信息
			$dsn = "{$this->dbConfig['db']}:host={$this->dbConfig['host']};port={$this->dbConfig['host']};dbname={$this->dbConfig['dbname']};charset={$this->dbConfig['charset']}";
			//实例化PDO
			$this->db = new PDO($dsn,$this->dbConfig['user'],$this->dbConfig['pass']);
			//设定字符集
			$this->db->query("set names {$this->dbConfig['charset']}");
			echo 1;
		}catch (PDOException $e){
			//错误提示
			die("数据库操作失败:{$e->getMessage()}");
		}
	}
	/**
	 * 执行SQL
	 * @param $sql string 执行的SQL语句
	 * @return object PDOStatement
	 */
	public function query($sql){
		$rst = $this->db->query($sql);
		if($rst===false){
			$error = $this->db->errorInfo();
			die("数据库操作失败:ERROR {$error[1]}({$error[0]}): {$error[2]}");
		}
		return $rst;
	}
	/**
	 * 取得一行结果
	 * @param $sql string 执行的SQL语句
	 * @return array 关联数组结果 
	 */
	public function fetchRow($sql){
		return $this->query($sql)->fetch(PDO::FETCH_ASSOC);
	}
	/**
	 * 取得所有结果
	 * @param $sql string 执行的SQL语句
	 * @return array 关联数组结果 
	 */
	public function fetchAll($sql){
		return $this->query($sql)->fetchAll(PDO::FETCH_ASSOC);
	}
	public function demo(){
		echo '测试内容';
	}
}

// // 调用方式
// // 连接数据库
// $pdo = MySQLPDO::getInstance();
// // 调用方法
// $pdo -> demo()

2)模型类
在实际项目中,通常是在一个数据库中建立多个表来管理数据,如下图。MVC中的模型,其实就是为项目中的每个表建立一个模型。如果用面向对象的思想,那么每个模型都是一个模型类,对表的所有操作,都要放到模型类中完成。

在这里插入图片描述
前面学习了数据库操作类,实例化数据库操作类是所有模型类都要经历的一步,因此需要一个基础模型类来完成这个任务。

例:

  • 创建基础模型类:
  • 创建Student模型类
<?php
/**
 * 基础模型类
 */
class model {
	protected $db; //保存数据库对象
	public function __construct(){
		$this->initDB(); // 初始化数据库
	}
	private function initDB(){
		//配置数据库连接信息
		$dbConfig = array('dbname'=>'mvc_study');
		//实例化数据库操作类
		$this->db = MySQLPDO::getInstance($dbConfig);
	}
}

<?php
/**
 * student表的操作类,继承基础模型类
 */
class studentModel extends model{
	/* 查询所有学生 */
	public function getAll(){
		$data = $this->db->fetchAll('select * from `student`');
		return $data;
	}
	/* 查询指定id的学生 */
	public function getByID($id){
		$data = $this->db->fetchRow("select * from `student` where id={$id}");
		return $data;
	}
}

3、创建控制器,将模型和视图整合

控制器是MVC应用程序中的指挥官,它接收用户的请求,并决定需要调用哪些模型进行处理,再用相应的视图显示从模型返回的数据,最后通过浏览器呈现给用户。
1)模块
如果用面向对象的方式实现控制器,就需要先理解模块(Module)的概念。一个成熟的项目是由多个模块组成的,每个模块又是一系列相关功能的集合。接下来通过一个图例来演示项目中的模块,如图所示:
在这里插入图片描述
2)控制器类
控制器是根据模块创建的,即每个模块对应一个控制器类 创建StudentController.class.php控制器类,实现的功能:

  • 查看所有学生信息
  • 查看指定学生信息
<?php
<?php
/*
 * @Descripttion: 
 * @version: 
 * @Author: wei
 * @Date: 2020-04-09 10:23:14
 * @LastEditors: wei
 * @LastEditTime: 2020-04-17 16:23:37
 */
/**
 * 学生模块控制器类
 */
class studentController{
	/**
	 * 学生列表
	 */
	public function listAction(){
		//实例化模型,取出数据
		$stu = new studentModel();
		$data = $stu->getAll();
		//载入视图文件
		require 'student_list.html';
	}
	/**
	 * 查看指定学生信息
	 */
	public function infoAction(){
		//接收请求参数
		$id = $_GET['id'];
		//实例化模型,取出数据
		$stu = new studentModel();
		$data = $stu->getById($id);

		//载入视图文件
		 require 'student_info.html';
	}
}


3)视图文件
根据控制器类要实现的功能方法,创建视图文件,这里没有创建,直接打印出数据代替了

  • 查看所有学生信息视图文件:student_list.html
  • 查看指定学生信息视图文件:student_info.html
  • student_list.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
table{border-collapse:collapse;text-align:center;}
a{text-decoration:none;}
</style>
</head>
<body>
<h1>学生列表</h1>
<table width="300" border="1">
  <tr><th>ID</th><th>姓名</td><th>操作</th></tr>
  <?php foreach($data as $v): ?>
  <tr>
    <td><?php echo $v['id']; ?></td>
    <td><?php echo $v['name']; ?></td>
    <td><a href="index.php?c=student&a=info&id=<?php echo $v['id']; ?>">查看</a></td>
  </tr>
  <?php endForeach; ?>
</table>
</body>
</html>

student_info.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
table{border-collapse:collapse;text-align:center;}
a{text-decoration:none;}
</style>
</head>
<body>
<h1>查看学生信息</h1>
<table width="300" border="1">
  <tr><th>ID</th><td><?php echo $data['id']; ?></td></tr>
  <tr><th>姓名</th><td><?php echo $data['name']; ?></td></tr>
  <tr><th>性别</th><td><?php echo $data['gender']; ?></td></tr>
  <tr><th>年龄</th><td><?php echo $data['age']; ?></td></tr>
</table>
<a href="index.php">返回</a>
</body>
</html>
5、前端控制器(入口文件index.php)

前端控制器也称为请求分发器(dispather),通过URL参数判断用户请求了哪个功能,然后完成相关控制器的加载、实例化、方法调用等操作。
使用MVC开发的是一种单一入口的应用程序,传统的Web程序是多入口的,即通过访问不同的文件来完成用户请求。
例如教务管理系统,管理学生时访问student.php,管理教师时访问teacher.php。
单入口程序只有一个index.php提供用户访问。

<?php
/**
 * 前端控制器
 */
header('Content-Type:text/html; charset=utf8');
//载入数据库操作类
require('MySQLPDO.class.php');
//载入模型文件
require 'model.class.php';
require 'studentModel.class.php';
//得到控制器名
$c = isset($_GET['c']) ? $_GET['c'] : 'student';
//载入控制器文件
require './'.$c.'Controller.class.php';
//实例化控制器(可变变量)
$controller_name = $c.'Controller';
$controller = new $controller_name;
//得到方法名
$action = isset($_GET['a']) ? $_GET['a'] : 'list';
//调用方法(可变方法)
$action_name = $action.'Action';
$controller->$action_name();

效果展示
在这里插入图片描述
在这里插入图片描述

posted @ 2022-04-02 09:47  coderwcb  阅读(376)  评论(0编辑  收藏  举报