PHP核心之MVC设计模式

MVC设计模式

MVC概述

  • MVC介绍
    • MVC是一个编程思想,是一种设计模式
    • 思想:将一个功能分解成3个部分
      • Model(模型):处理与数据有关的逻辑
      • View(视图):显示页面
      • Controller(控制器):处理业务逻辑
    • 控制器用来接收请求
    • 以后不能直接请求模型和视图

MVC演化

显示商品

# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
//连接数据库
$param=array(
	'user'	=>	'root',
    'pwd'	=>	'',
    'dbname' => 'data'
);
$mypdo= MyPDO::getInstance($param);
//获取商品数据
$list=$mypdo->fetchAll('select * from products');
?>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> <th>名称</th> <th>价格</th> <th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>

演化一:分离视图

# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
//连接数据库
$param=array(
	'user'	=>	'root',
    'pwd'	=>	'',
    'dbname' => 'data'
);
$mypdo= MyPDO::getInstance($param);
//获取商品数据
$list=$mypdo->fetchAll('select * from products');
require './products_list.html';
?>
# products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> <th>名称</th> <th>价格</th> <th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>

演化二:分离模型

  • 模型的规则
    • 一个表对应一个模型,表名和模型名必须一致
    • 模型以Model结尾(不是必须的)
# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
// 实例化数据模型
$model= new ProductsModel();
$list= $model->getList();
// 加载视图
require './products_list.html';
?>
# products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> <th>名称</th> <th>价格</th> <th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>
# ProductsModel.class.php
<?php
//products模型用来操作products表
class ProductsModel {
    // 获取products表的数据
    public function getList(){
        // 连接数据库
        $param= array(
            'user' => 'root',
            'pwd' => '',
            'dbname' => 'data'
        );
        $mypdo= MyPDO::getInstance($param);
        // 获取商品数据
        return $mypdo->fetchAll('select * from products');
    }
}
?>

演化三:分离基础模型

  • 概念
    • 连接数据库的代码每个模型都要使用
    • 所有我们需要将连接数据库的代码封装到基础模型类中(Model)
# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
// 实例化数据模型
$model= new ProductsModel();
$list= $model->getList();
// 加载视图
require './products_list.html';
?>
# products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> <th>名称</th> <th>价格</th> <th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>
# Model.class.php
<?php
// 基础模型
class Model {
    protected $mypdo;
    public function __construct(){
        $this->initMyPDO();
    }
    // 连接数据库
    private function initMyPDO(){
        $param= array(
            'user' => 'root',
            'pwd' => '',
            'dbname' => 'data'
        );
        $this->mypdo= MyPDO::getInstance($param);
    }
}
?>
# ProductsModel.class.php
<?php
//products模型用来操作products表
class ProductsModel extends Model{
    // 获取products表的数据
    public function getList(){
        // 获取商品数据
        return $this->mypdo->fetchAll('select * from products');
    }
}
?>

演化四:分离控制器

  • 概念

    • 控制器代码放在index.php页面中是不合理的
    • 因为项目中的控制器会很多,而index.php只有一个
    • 所以需要将控制器分离开来
  • 控制器的规则

    • 一个模块必须对应一个控制器
    • 控制器以Controller结尾(不是必须的)
    • 控制器中的方法以Action结尾(不是必须的)
      • 目的防止方法名是PHP关键字
  • 请求分发

    • 每次请求都要从index.php进入,所以index.php又叫入口文件
    • 通过在url地址上传递参数来寻址
      • c 控制器
      • a 方法
# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
//确定路由
$c= $_GET['c']??'Products';   		//控制器
$a= $_GET['a']??'list';				//方法
$c= ucfirst(strtolower($c));		//首字母大写
$a= strtolower($a);					//转成小写
$controller_name= $c.'Controller';	//拼接控制器类名
$action_name= $a.'Action';			//拼接方法名
//请求分发
$obj= new $controller_name();
$obj->$action_name();
?>
# products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> <th>名称</th> <th>价格</th> <th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>
# Model.class.php
<?php
// 基础模型
class Model {
    protected $mypdo;
    public function __construct(){
        $this->initMyPDO();
    }
    // 连接数据库
    private function initMyPDO(){
        $param= array(
            'user' => 'root',
            'pwd' => '',
            'dbname' => 'data'
        );
        $this->mypdo= MyPDO::getInstance($param);
    }
}
?>
# ProductsModel.class.php
<?php
//products模型用来操作products表
class ProductsModel extends Model{
    // 获取products表的数据
    public function getList(){
        // 获取商品数据
        return $this->mypdo->fetchAll('select * from products');
    }
}
?>
# ProductsController.class.php
<?php
// 商品模块
class ProductsController {
    // 获取商品列表
    public function listAction(){
        // 实例化数据模型
        $model= new ProductsModel();
        $list= $model->getList();
        // 加载视图
        require './products_list.html';
    }
}
?>

删除商品

# index.php
<?php
//自动加载类
spl_autoload_register(function($class_name){
	require "./{$class_name}.class.php";
});
//确定路由
$c= $_GET['c']??'Products';   		//控制器
$a= $_GET['a']??'list';				//方法
$c= ucfirst(strtolower($c));		//首字母大写
$a= strtolower($a);					//转成小写
$controller_name= $c.'Controller';	//拼接控制器类名
$action_name= $a.'Action';			//拼接方法名
//请求分发
$obj= new $controller_name();
$obj->$action_name();
?>
# products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> 
			<th>名称</th> 
			<th>价格</th> 
			<th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="index.php?c=Products&a=del&proid=<?=$rows['proID']?>" onclick="return confirm('确定要删除吗')">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>
# ProductsController.class.php
<?php
// 商品模块
class ProductsController {
    // 获取商品列表
    public function listAction(){
        // 实例化数据模型
        $model= new ProductsModel();
        $list= $model->getList();
        // 加载视图
        require './products_list.html';
    }
    public function delAction(){
        $id= (int)$_GET['proid'];
        $model= new ProductsModel();
        if($model->del($id)){
            header('location:index.php?c=Products&a=list');
        }else{
            echo '删除失败!';
            exit;
        }
    }
}
?>
# ProductsModel.class.php
<?php
//products模型用来操作products表
class ProductsModel extends Model{
    // 获取products表的数据
    public function getList(){
        // 获取商品数据
        return $this->mypdo->fetchAll('select * from products');
    }
    // 删除products表的数据
    public function del($proid){
        // 删除商品数据
        return $this->mypdo->exec("delete from products where proID={$proid}");
    }
}
?>

框架目录

创建目录结构

  • Application 应用程序

    • Config 配置文件
    • Controller 控制器
      • Admin 后台控制器
      • Home 前台控制器
    • Model 模型
    • View 视图
      • Admin 后台视图
      • Home 前台视图
  • Framework 框架

    • Core 核心
    • Lib 扩展
  • Public 静态资源

  • Traits 复用代码

文件分类存放

  • 概念

    • 由于每次都请求入口文件,所以”.“表示入口文件所在的目录
  • Application

    • Config
      • config.php
    • Controller
      • Admin
        • ProductsController.class.php
      • Home
    • Model
      • ProductsModel.class.php
    • View
      • Admin
        • products_list.html
      • Home
  • Framework

    • Core
      • Framework.class.php
      • Model.class.php
      • MyPDO.class.php
    • Lib
  • Public

    • images
      • error.fw.png
      • success.fw.png
  • Traits

    • Jump.class.php
  • index.php

添加命名空间

  • 概念
    • 通过文件目录地址做命名空间
    • 这样获取了命名空间就能知道文件存放的地址
# Model.class.php
<?php
namespace Core;
class Model {
    ...
}
?>
# MyPDO.class.php
<?php
namespace Core;
class MyPDO {
    ...
}
?>
# ProductsModel.class.php
<?php
namespace Model;
class ProductsModel extends Model {
    ...
}
?>
# ProductsController.class.php
<?php
namespace ControllerAdmin;
class ProductsController {
    ...
}
?>

框架类实现

定义路径常量

  • 概念

    • 由于文件路径使用频率很高,而且路径比较长
    • 所以将固定不变的路径定义成路径常量
  • 知识点

    • getcwd() 入口文件的绝对路径
    • windows下默认的目录分隔符是,Linux下默认的目录分隔符是/
    • DIRECTORY_SEPARATOR常量根据不同的操作系统返回不同的目录分隔符
# Framework.class.php
private static function initConst(){
    define('DS', DIRECTORY_SEPARATOR);  //定义目录分隔符
    define('ROOT_PATH', getcwd().DS);  //入口文件所在的目录
    define('APP_PATH', ROOT_PATH.'Application'.DS);   //application目录
    define('CONFIG_PATH', APP_PATH.'Config'.DS);
    define('CONTROLLER_PATH', APP_PATH.'Controller'.DS);
    define('MODEL_PATH', APP_PATH.'Model'.DS);
    define('VIEW_PATH', APP_PATH.'View'.DS);
    define('FRAMEWORK_PATH', ROOT_PATH.'Framework'.DS);
    define('CORE_PATH', FRAMEWORK_PATH.'Core'.DS);
    define('LIB_PATH', FRAMEWORK_PATH.'Lib'.DS);
    define('TRAITS_PATH', ROOT_PATH.'Traits'.DS);
}

引入配置文件

  • 概述
    • 在PHP7.0之前,常量不能保存数组和对象
# config.php
return array(
    //数据库配置
    'database'=>array(),
    //应用程序配置
    'app'=>array(
        'dp' => 'Admin',        //默认平台
        'dc' => 'Products',     //默认控制器
        'da' => 'list'          //默认方法
    )
);
# Framework.class.php
private static function initConfig(){
    $GLOBALS['config']= require CONFIG_PATH.'config.php';
}

确定路由

  • 概述
    • p 平台[platform]
    • c 控制器[controller]
    • a 方法[action]
# Framework.class.php
private static function initRoutes(){
    $p= $_GET['p']??$GLOBALS['config']['app']['dp'];
    $c= $_GET['c']??$GLOBALS['config']['app']['dc'];
    $a= $_GET['a']??$GLOBALS['config']['app']['da'];
    $p= ucfirst(strtolower($p));
    $c= ucfirst(strtolower($c));		
    $a= strtolower($a);			
    define('PLATFROM_NAME', $p);    //平台名常量
    define('CONTROLLER_NAME', $c);  //控制器名常量
    define('ACTION_NAME', $a);      //方法名常量
    define('__URL__', CONTROLLER_PATH.$p.DS);   //当前请求控制器的目录地址
    define('__VIEW__',VIEW_PATH.$p.DS);     //当前视图的目录地址
}

自动加载类

# Framework.class.php
private static function initAutoLoad(){
    spl_autoload_register(function($class_name){
        $namespace= dirname($class_name);   //命名空间
        $class_name= basename($class_name); //类名
        if(in_array($namespace, array('Core','Lib')))   //命名空间在Core和Lib下
            $path= FRAMEWORK_PATH.$namespace.DS.$class_name.'.class.php';
        elseif($namespace=='Model')     //文件在Model下
            $path=MODEL_PATH.$class_name.'.class.php';
        elseif($namespace=='Traits')    //文件在Traits下
            $path=TRAITS_PATH.$class_name.'.class.php';
        else   //控制器
            $path=CONTROLLER_PATH.PLATFROM_NAME.DS.$class_name.'.class.php'; 
        if(file_exists($path) && is_file($path))
            require $path;
    });
}

请求分发

# Framework.class.php
private static function initDispatch(){
    $controller_name='Controller\'.PLATFROM_NAME.'\'.CONTROLLER_NAME.'Controller';	//拼接控制器类名
    $action_name=ACTION_NAME.'Action';	//拼接方法名
    $obj=new $controller_name();
    $obj->$action_name();
} 

封装run()方法

# Framework.class.php
class Framework{
    //启动框架
    public static function run(){
        self::initConst();
        self::initConfig();
        self::initRoutes();
        self::initAutoLoad();
        self::initDispatch();
    }
}

在入口中调用run()方法

  • 概述
    • run()方法调用后就启动了框架
# index.php
<?php
require './Framework/Core/Framework.class.php';
Framework::run();
?>

SQL方法封装

生成insert语句

  • 知识点
    • array_keys($arr) 返回数组的键
    • array_values($arr) 返回数组的值
    • array_map(fun(), $arr) 将函数作用到数组中的每个值上,并返回带有新值的数组
$table= 'products';	//表名
//插入的数据
$data['proid']='007';
$data['proname']='钢笔';
$data['proprice']=120;
//第一步:拼接字段名
$keys=array_keys($data);		//获取所有的字段名
$keys=array_map(function($key){	//在所有的字段名上添加反引号
	return "`{$key}`";
},$keys);
$keys=implode(',',$keys);		//字段名用逗号连接起来
//第二步:拼接值
$values=array_values($data);	//获取所有的值
$values=array_map(function($value){	//所有的值上添加单引号
	return "'{$value}'";
},$values);
$values=implode(',',$values);	//值通过逗号连接起来
//第三步:拼接SQL语句
echo $sql="insert into `{$table}` ($keys) values ($values)";

生成更新语句

  • 知识点
    • array_search(value, $arr) 在数组中搜索某个键值,并返回对应的键名
$table='products';	                //表名
$data['proname']='钢笔';
$data['proprice']=120;
$data['proID']='111';
//获取主键
function getPrimaryKey($table) {
	//连接数据库
	$link=mysqli_connect('localhost','root','root','data');
	mysqli_set_charset($link,'utf8');
	//查看表结构
	$rs=mysqli_query($link,"desc `{$table}`");
	//循环判断主键
	while($rows=mysqli_fetch_assoc($rs)){
		if($rows['Key']=='PRI')
			return $rows['Field'];
	}
}
//第一步:获取非主键
$keys=array_keys($data);	    //获取所有键
$pk=getPrimaryKey($table);	    //获取主键
$index=array_search($pk,$keys);	//返回主键在数组中的下标
unset($keys[$index]);		    //删除主键
//第二步:拼接`键`='值'的形式
$keys=array_map(function($key) use ($data){
	return "`{$key}`='{$data[$key]}'";
},$keys);
$keys=implode(',',$keys);
//第三步:拼接SQL语句
echo $sql="update `{$table}` set $keys where $pk='{$data[$pk]}'";

生成select语句

  • 知识点
    • is_array($arr) 判断变量是否为数组
function select($table,$cond=array()) {
	$sql="select * from `{$table}` where 1";
	//拼接条件
	if(!empty($cond)){
		foreach($cond as $k=>$v){
			if(is_array($v)){	        //条件的值是数组类型
				switch($v[0]){	        //$v[0]保存的是符号,$v[1]是值
					case 'eq':		    //等于  equal
						$op='=';
						break;
					case 'gt':		    //大于  greater than
						$op='>';
						break;
					case 'lt':
						$op='<';
						break;
					case 'gte':
					case 'egt':
						$op='>=';
						break;
					case 'lte':
					case 'elt':
						$op='<=';
						break;
					case 'neq':
						$op='<>';
						break;
				}
				$sql.=" and `$k` $op '$v[1]'";
			}else{
				$sql.=" and `$k`='$v'";
			}
		}
	}
	return $sql;
}
//测试
$table='products';	//表名
$cond=array(
	'proname'	=>	'钢笔',
	'proprice'	=>	array('eq','12'),
	'aa'	=>	array('gt',10),
	'bb'	=>	array('lt',20),
);
echo select($table),'<br>';
echo select($table,$cond);

获取表名

  • 知识点
    • get_class($this) 返回实例对象的类(包括命名空间)
    • basename($path) 返回路径中的文件名部分
    • substr($str, startNum, endNum) 截取字符串
class Model {
	private $table;
	public function __construct($table='') {
		if($table!='')		//直接给基础模型传递表名
			$this->table=$table;
		else {				//实例化子类模型
			$this->table=substr(basename(get_class($this)),0,-5);
		}
		echo $this->table,'<br>';
	}
}

在项目中封装万能的增、删、改、查

  • 概念
    • 由于封装的方法可以操作所有的表
    • 可以将这些方法封装在基础模型中
<?php
namespace Core;
//基础模型
class Model {
    protected $mypdo;
    private $table; //表名
    private $pk;    //主键
    public function __construct($table=''){
        $this->initMyPDO();
        $this->initTable($table);
        $this->getPrimaryKey();
    }
    //连接数据库
    private function initMyPDO() {
        $this->mypdo= MyPDO::getInstance($GLOBALS['config']['database']);
    }
    //获取表名
    private function initTable($table){
        if($table!='')		//直接给基础模型传递表名
            $this->table=$table;
        else {				//实例化子类模型
            $this->table=substr(basename(get_class($this)),0,-5);
        }
    }
    //获取主键
    private function getPrimaryKey() {
        $rs=$this->mypdo->fetchAll("desc `{$this->table}`");
        foreach($rs as $rows){
            if($rows['Key']=='PRI'){
                $this->pk=$rows['Field'];
                break;
            }
        }
    }
    //万能的插入
    public function insert($data){
        $keys=array_keys($data);		//获取所有的字段名
        $keys=array_map(function($key){	//在所有的字段名上添加反引号
                return "`{$key}`";
        },$keys);
        $keys=implode(',',$keys);		//字段名用逗号连接起来
        $values=array_values($data);	//获取所有的值
        $values=array_map(function($value){	//所有的值上添加单引号
                return "'{$value}'";
        },$values);
        $values=implode(',',$values);	//值通过逗号连接起来
        $sql="insert into `{$this->table}` ($keys) values ($values)";
        return $this->mypdo->exec($sql);
    }
    //万能的更新
    public function update($data){
        $keys=array_keys($data);	//获取所有键
        $index=array_search($this->pk,$keys);	//返回主键在数组中的下标
        unset($keys[$index]);		//删除主键
        $keys=array_map(function($key) use ($data){
                return "`{$key}`='{$data[$key]}'";
        },$keys);
        $keys=implode(',',$keys);
        $sql="update `{$this->table}` set $keys where $this->pk='{$data[$this->pk]}'";
        return $this->mypdo->exec($sql);
    }
    //删除
    public function delete($id){
        $sql="delete from `{$this->table}` where `{$this->pk}`='$id'";
        return $this->mypdo->exec($sql);
    }
    //查询,返回二维数组
    public function select($cond=array()){
        $sql="select * from `{$this->table}` where 1";
        if(!empty($cond)){
            foreach($cond as $k=>$v){
                if(is_array($v)){	        //条件的值是数组类型
                    switch($v[0]){	    //$v[0]保存的是符号,$v[1]是值
                        case 'eq':		//等于  equal
                            $op='=';
                            break;
                        case 'gt':		//大于  greater than
                            $op='>';
                            break;
                        case 'lt':
                            $op='<';
                            break;
                        case 'gte':
                        case 'egt':
                            $op='>=';
                            break;
                        case 'lte':
                        case 'elt':
                            $op='<=';
                            break;
                        case 'neq':
                            $op='<>';
                            break;
                    }
                    $sql.=" and `$k` $op '$v[1]'";
                }else{
                    $sql.=" and `$k`='$v'";
                }
            }
        }
        return $this->mypdo->fetchAll($sql);
    }
    //查询,返回一维数组
    public function find($id){
        $sql="select * from `{$this->table}` where `{$this->pk}`='$id'";
        return $this->mypdo->fetchRow($sql);
    }
}
?>

MVC框架代码

入口文件

# index.php
<?php
require './Framework/Core/Framework.class.php';
Framework::run();
?>

框架文件

# Framework/Core/Framework.class.php
<?php
class Framework{
    //启动框架
    public static function run(){
        self::initConst();
        self::initConfig();
        self::initRoutes();
        self::initAutoLoad();
        self::initDispatch();
    }
    //定义路径常量
    private static function initConst(){
        define('DS', DIRECTORY_SEPARATOR);  //定义目录分隔符
        define('ROOT_PATH', getcwd().DS);  //入口文件所在的目录
        define('APP_PATH', ROOT_PATH.'Application'.DS);   //application目录
        define('CONFIG_PATH', APP_PATH.'Config'.DS);
        define('CONTROLLER_PATH', APP_PATH.'Controller'.DS);
        define('MODEL_PATH', APP_PATH.'Model'.DS);
        define('VIEW_PATH', APP_PATH.'View'.DS);
        define('FRAMEWORK_PATH', ROOT_PATH.'Framework'.DS);
        define('CORE_PATH', FRAMEWORK_PATH.'Core'.DS);
        define('LIB_PATH', FRAMEWORK_PATH.'Lib'.DS);
        define('TRAITS_PATH', ROOT_PATH.'Traits'.DS);
    }
    //引入配置文件
    private static function initConfig(){
       $GLOBALS['config']=require CONFIG_PATH.'config.php';
    }
    //确定路由
    private static function initRoutes(){
        $p=$_GET['p']??$GLOBALS['config']['app']['dp'];
        $c=$_GET['c']??$GLOBALS['config']['app']['dc'];
        $a=$_GET['a']??$GLOBALS['config']['app']['da'];
        $p=ucfirst(strtolower($p));
        $c=ucfirst(strtolower($c));		//首字母大写
        $a=strtolower($a);			//转成小写
        define('PLATFROM_NAME', $p);    //平台名常量
        define('CONTROLLER_NAME', $c);  //控制器名常量
        define('ACTION_NAME', $a);      //方法名常量
        define('__URL__', CONTROLLER_PATH.$p.DS);   //当前请求控制器的目录地址
        define('__VIEW__',VIEW_PATH.$p.DS);     //当前视图的目录地址
    }
    //自动加载类
    private static function initAutoLoad(){
        spl_autoload_register(function($class_name){
            $namespace= dirname($class_name);   //命名空间
            $class_name= basename($class_name); //类名
            if(in_array($namespace, array('Core','Lib')))   //命名空间在Core和Lib下
                $path= FRAMEWORK_PATH.$namespace.DS.$class_name.'.class.php';
            elseif($namespace=='Model')     //文件在Model下
                $path=MODEL_PATH.$class_name.'.class.php';
            elseif($namespace=='Traits')    //文件在Traits下
                $path=TRAITS_PATH.$class_name.'.class.php';
            else   //控制器
                $path=CONTROLLER_PATH.PLATFROM_NAME.DS.$class_name.'.class.php'; 
            if(file_exists($path) && is_file($path))
                require $path;
        });
    }
    //请求分发
    private static function initDispatch(){
        $controller_name='Controller\'.PLATFROM_NAME.'\'.CONTROLLER_NAME.'Controller';	//拼接控制器类名
        $action_name=ACTION_NAME.'Action';	//拼接方法名
        $obj=new $controller_name();
        $obj->$action_name();
    } 
}

配置文件

# Application/Config/config.php
<?php
return array(
    //数据库配置
    'database'=>array(),
    //应用程序配置
    'app'=>array(
        'dp' => 'Admin',        //默认平台
        'dc' => 'Products',     //默认控制器
        'da' => 'list'          //默认方法
    )
);
?>

基础模型

# Framework/Core/Model.class.php
<?php
namespace Core;
class Model {
    protected $mypdo;
    public function __construct(){
        $this->initMyPDO();
    }
    // 连接数据库
    private function initMyPDO(){
        $this->mypdo= MyPDO::getInstance($GLOBALS['config']['database']);
    }
}
?>

PDO数据库

# Framework/Core/MyPDO.class.php
<?php
namespace Core;
class MyPDO{
    private $type;      //数据库类别
    private $host;      //主机地址
    private $port;      //端口号
    private $dbname;    //数据库名
    private $charset;   //字符集
    private $user;      //用户名
    private $pwd;       //密码
    private $pdo;       //保存PDO对象
    private static $instance;
    private function __construct($param) {
        $this->initParam($param);
        $this->initPDO();
        $this->initException();
    }
    private function __clone() {
    }
    public static function getInstance($param=array()){
        if(!self::$instance instanceof self)
            self::$instance=new self($param);
        return self::$instance;
    }
    //初始化参数
    private function initParam($param){
        $this->type=$param['type']??'mysql';
        $this->host=$param['host']??'127.0.0.1';
        $this->port=$param['port']??'3306';
        $this->dbname=$param['dbname']??'data';
        $this->charset=$param['charset']??'utf8';
        $this->user=$param['user']??'root';
        $this->pwd=$param['pwd']??'';
    }
    //初始化PDO
    private function initPDO(){
        try{
            $dsn="{$this->type}:host={$this->host};port={$this->port};dbname={$this->dbname};charset={$this->charset}";
            $this->pdo=new PDO($dsn, $this->user, $this->pwd);
        } catch (PDOException $ex) {
            $this->showException($ex);
            exit;
        }
    }
    
    //显示异常
    private function showException($ex,$sql=''){
        if($sql!=''){
            echo 'SQL语句执行失败<br>';
            echo '错误的SQL语句是:'.$sql,'<br>';
        }
        echo '错误编号:'.$ex->getCode(),'<br>';
        echo '错误行号:'.$ex->getLine(),'<br>';
        echo '错误文件:'.$ex->getFile(),'<br>';
        echo '错误信息:'.$ex->getMessage(),'<br>';
    }
    //设置异常模式
    private function initException(){
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
    }

    //执行增、删、改操作
    public function exec($sql){
        try{
            return $this->pdo->exec($sql);
        } catch (PDOException $ex) {
            $this->showException($ex, $sql);
            exit;
        }
    }
    //获取自动增长的编号
    public function lastInsertId(){
        return $this->pdo->lastInsertId();
    }

    //判断匹配的类型
    private function fetchType($type){
        switch ($type){
            case 'num':
                return PDO::FETCH_NUM;
            case 'both':
                return PDO::FETCH_BOTH;
            case 'obj':
                return PDO::FETCH_OBJ;
            default:
                return PDO::FETCH_ASSOC;
        }
    }
    //获取所有数据 ,返回二维数组
    public function fetchAll($sql,$type='assoc'){
        try{
            $stmt=$this->pdo->query($sql);  //获取PDOStatement对象
            $type= $this->fetchType($type); //获取匹配方法
            return $stmt->fetchAll($type);
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
        }
    }
    //获取一维数组
    public function fetchRow($sql,$type='assoc'){
        try{
            $stmt=$this->pdo->query($sql);  //获取PDOStatement对象
            $type= $this->fetchType($type); //获取匹配方法
            return $stmt->fetch($type);
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
            exit;
        }
    }
    //返回一行一列
    public function fetchColumn($sql){
        try{
             $stmt=$this->pdo->query($sql);
            return $stmt->fetchColumn();
        } catch (Exception $ex) {
            $this->showException($ex, $sql);
            exit;
        }
    }
}
?>

控制器

# Application/Controller/Admin/ProductsController.class.php
<?php
namespace ControllerAdmin;
// 商品模块
class ProductsController {
    use TraitsJump;
    // 获取商品列表
    public function listAction(){
        // 实例化数据模型
        $model= new ModelProductsModel();
        $list= $model->getList();
        // 加载视图
        require __VIEW__.'products_list.html';
    }
    public function delAction(){
        $id= (int)$_GET['proid'];
        $model= new ModelProductsModel();
        if($model->del($id)){
            $this->success('index.php?p=Admin&c=Products&a=list', '删除成功');
        }else{
            $this->error('index.php?p=admin&c=Products&a=list', '删除失败');
        }
    }
}
?>

方法模型

# Application/Model/ProductsModel.class.php
<?php
namespace Model;
//products模型用来操作products表
class ProductsModel extends CoreModel{
    // 获取products表的数据
    public function getList(){
        // 获取商品数据
        return $this->mypdo->fetchAll('select * from products');
    }
    // 删除products表的数据
    public function del($proid){
        // 删除商品数据
        return $this->mypdo->exec("delete from products where proID={$proid}");
    }
}
?>

视图

# Application/View/Admin/products_list.html
<!Doctype html>
<html>
<head>
<meta charset="utf-8">
<title>显示商品</title>
</head>
<body>
	<table border='1' width='980' bordercolor='#000'>
		<tr>
			<th>编号</th> 
			<th>名称</th> 
			<th>价格</th> 
			<th>删除</th>
		</tr>
		<?php foreach($list as $rows):?>
		<tr>
			<td><?=$rows['proID']?></td>
			<td><?=$rows['proname']?></td>
			<td><?=$rows['proprice']?></td>
			<td><a href="index.php?p=Admin&c=Products&a=del&proid=<?=$rows['proID']?>" onclick="return confirm('确定要删除吗')">删除</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>

复用跳转

# Traits/Jump.class.php
<?php
//跳转的插件
namespace Traits;
trait Jump{
    //封装成功的跳转
    public function success($url,$info='',$time=1){
        $this->redirect($url, $info, $time, 'success');
    }
    //封装失败跳转
    public function error($url,$info='',$time=3){
        $this->redirect($url, $info, $time, 'error');
    }
    /*
     * 作用:跳转的方法
     * @param $url string 跳转的地址
     * @param $info string 显示信息
     * @param $time int 停留时间
     * @param $flag string 显示模式  success|error
     */
    private function redirect($url,$info,$time,$flag){
        if($info=='')
            header ("location:{$url}");
        else{
          echo <<<str
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <!--
                <meta http-equiv="refresh" content="3;http://www.php.com"/>
                -->
                <title>Document</title>
            <style>
            body{
                text-align: center;
                font-family: '微软雅黑';
                font-size: 18px;
            }
            #success,#error{
                font-size: 36px;
                margin: 10px auto;
            }
            #success{
                color: #090;
            }
            #error{
                color: #F00;
            }
            </style>
            </head>
            <body>
                <img src="./Public/images/{$flag}.fw.png">
                <div id='{$flag}'>{$info}</div>
                <div><span id='t'>{$time}</span>秒以后跳转</div>
            </body>
            </html>
            <script>
            window.onload=function(){
                var t={$time};
                setInterval(function(){
                    document.getElementById('t').innerHTML=--t;
                    if(t==0)
                        location.href='index.php';
                },1000)
            }
            </script>
            str;
        exit;
        }
    }
}
原文地址:https://www.cnblogs.com/SharkJiao/p/14145882.html