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;
}
}
}