PHP核心之MVC项目架构

  • GitHub地址:https://github.com/wing1377/PHP-

入口文件

# 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;
    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);
    }
}
?>

连接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/Model/ProductsModel.class.php
<?php
namespace Model;
//products模型用来操作products表
class ProductsModel extends \Core\Model{
  
}
?>

子控制器

# Application/Controller/Admin/ProductsController.class.php
<?php
namespace Controller\Admin;
// 商品模块
use Core\Controller;    //引入基础控制器
class ProductsController extends \Core\Controller {
    use \Traits\Jump;
    // 获取商品列表
    public function listAction(){
        // 实例化数据模型
        $model= new \Model\ProductsModel();
        $list= $model->select();
        // 加载视图
        require __VIEW__.'products_list.html';
    }
    public function delAction(){
        $id= (int)$_GET['proid'];
        $model= new \Model\ProductsModel();
        if($model->delete($id)){
            $this->success('index.php?p=Admin&c=Products&a=list', '删除成功');
        }else{
            $this->error('index.php?p=admin&c=Products&a=list', '删除失败');
        }
    }
    public function addAction(){
        //执行添加逻辑
        if(!empty($_POST)){
            $model=new \Core\Model('products');
            if($model->insert($_POST))
                $this->success ('index.php?p=Admin&c=Products&a=list', '插入成功');
            else
                $this->error ('index.php?p=Admin&c=Products&a=add', '插入失败');
        }
        //显示添加页面
        require __VIEW__.'products_add.html';
    }
    public function editAction(){
        $proid=$_GET['proid'];  //需要修改的商品id
        $model=new \Core\Model('products');
        //执行修改逻辑
        if(!empty($_POST)){
            $_POST['proID']=$proid;
            if($model->update($_POST))
                $this->success ('index.php?p=Admin&c=Products&a=list', '修改成功');
            else
                $this->error ('index.php?p=Admin&c=Products&a=edit&proid='.$proid, '修改失败');
        }
        //显示商品
        $info= $model->find($proid);
        require __VIEW__.'products_edit.html';
    }
}
?>

商品视图

# 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'>
		<a href="index.php?p=Admin&c=Products&a=add">添加商品</a>
		<tr>
			<th>编号</th> 
			<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>
			<td><a href="index.php?p=Admin&c=Products&a=edit&proid=<?=$rows['proID']?>">修改</a></td>
		</tr>
		<?php endforeach;?>
	</table>
</body>
</html>

添加视图

# Application/View/Admin/products_add.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>添加商品</title>
</head>
<body>
    <form method="post" action="">
        名称: <input type="text" name="proname"> <br />
        价格: <input type="text" name="proprice"> <br />
        <input type="submit" value="提交">
    </form>
</body>
</html>

更新视图

# Application/View/Admin/products_edit.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form method="post" action="">
        名称: <input type="text" name="proname" value='<?=$info['proname']?>'> <br />
        价格: <input type="text" name="proprice" value='<?=$info['proprice']?>'> <br />
        <!--
        <input type="hidden" name="proID" value=<?=$info['proID']?>>
        -->
        <input type="submit" value="提交">
    </form>
</body>
</html>

启动Session

# Framework\Lib\Session.class.php
<?php
namespace Lib;
class Session{
    private $mypdo;
    public function __construct() {
        session_set_save_handler(
            [$this,'open'],
            [$this,'close'],
            [$this,'read'],
            [$this,'write'],
            [$this,'destroy'],
            [$this,'gc']
        );
        session_start();
    }
    public function open() {
        $this->mypdo= \Core\MyPDO::getInstance($GLOBALS['config']['database']);
        return true;
    }
    //关闭会话
    public function close() {
        return true;
    }
    //读取会话
    public function read($sess_id) {
        $sql="select sess_value from sess where sess_id='$sess_id'";
        return (string)$this->mypdo->fetchColumn($sql);
    }
    //写入会话
    public function write($sess_id,$sess_value) {
        $sql="insert into sess values ('$sess_id','$sess_value',unix_timestamp()) on duplicate key update sess_value='$sess_value',sess_time=unix_timestamp()";
        return $this->mypdo->exec($sql)!==false;
    }
    //销毁会话
    public function destroy($sess_id) {
        $sql="delete from sess where sess_id='$sess_id'";
        return $this->mypdo->exec($sql)!==false;
    }
    //垃圾回收
    public function gc($lifetime) {
        $expires=time()-$lifetime;	//过期时间点
        $sql="delete from sess where sess_time<$expires";
        return $this->mypdo->exec($sql)!==false;
    }
}
?>

基础控制器

# Framework\Core\Controller.class.php
<?php
//基础控制器
namespace Core;
class Controller{
    public function __construct() {
        $this->initSession();
    }
    //初始化session
    private function initSession(){
        new \Lib\Session();
    }
}
?>
posted @ 2020-12-18 15:08  wing1377  阅读(288)  评论(0编辑  收藏  举报