• 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;
            }
        }
    }
    
  • 相关阅读:
    为PHP开发C语言扩展
    为PHP开发C++扩展
    PHP 7 vs HHVM性能对比
    Real-time storage area network
    JS书写优化
    JS书写优化
    数据库 10 大常见安全问题盘点~
    数据库 10 大常见安全问题盘点~
    数据库 10 大常见安全问题盘点~
    SQL Server 数据库定时自动备份
  • 原文地址:https://www.cnblogs.com/SharkJiao/p/14145882.html
Copyright © 2020-2023  润新知