PHP source code to implement MVC structure micro-framework

不言
Release: 2023-04-02 13:26:01
Original
3125 people have browsed it

This article mainly introduces the implementation of MVC structure micro-framework in PHP source code. It has certain reference value. Now I share it with you. Friends in need can refer to it.

Main:

  1. Constant optimization path

  2. Auto-loading class

  3. Optimization entry file

  4. Secure Access Project Directory


##

----------------------------------------------------
blog
├─App
│  ├─Model 模型
│  │  └─UserModel.class.php 用户模型类    
│  ├─View 视图
│  │  ├─Back后台
│  │  │  └─Index
│  │  │          └─index.html  后台首页面
│  │  └─Home前台
│  │      └─User 用户视图目录
│  │             └─login.html  登录表单页面
│  ├─Controller 控制器
│  │  ├─Back后台
│  │  │  └─IndexController.class.php 后台首页控制器
│  │  └─Home前台
│  │      └─UserController.class.php 用户控制器
├─Public   静态公共文件(js,css,images)
│  ├─Plugins 插件
│  │  └─layui 前端框架插件
│  ├─Back后台
│  │    ├─js/   js文件
│  │    ├─css/  css样式文件
│  │    └─image img图片 
│  └─Home前台
│      ├─js/   js文件
│      ├─css/  css样式文件
│      └─image img图片 
├─Frame 公共使用的类
│   ├─BaseModel.class.php 数据库连接类
│   ├─BaseController.class.php 控制器公共操作(设置编码,信息跳转)
│   ├─FactoryModel.class.php  模型工厂类
│   ├─Init.class.php  初始化应用类
│   └─MySQLDB.class.php 数据库操作工具类
└─index.php  入口文件
-----------------------------------------------------------------
Copy after login

##In the previous article, 4 questions were raised to be solved. This article This article focuses on solving these four problems and finally forming a complete micro-MVC framework structure. Subsequent blog projects or other projects can directly use this framework structure for development and learning.

Download and view the source code of the project: https://gitee.com/NewbiesYang/young_blog

Constant optimization path

Preparation: Create a branch

1 $ git checkout master
2 $ git checkout -b "MVC"
Copy after login

Ideas

1) Define commonly used directory paths as constants. Such as model directory, controller directory, etc.

2) Introduce classes and use defined constants to replace part of the path. Such as include FRAME.BaseModel.class.php

3) When loading the view, use constants to replace part of the path, such as include VIEW.'login.html' Simple form

Code implementation

1) Operation steps

step 1: 在入口文件中定义所需要的常量

step 2: 控制器中引入视图时, 使用常量进行优化
Copy after login

Operation step ideas

2) Define common path constants in the entry file 【index.php】

 1 <?php 
 2 /** 
 3  * 入口文件 
 4  */ 
 5 $p = !empty($_GET[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台 
 6 $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器 
 7 $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作 
 8  
 9 define(&#39;PLAT&#39;, $p);  //平台常量
 10 define(&#39;CTR&#39;, $c);  //控制器
 11 define(&#39;ACTION&#39;, $a); //动作
 12 
 13 
 14 define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 15 define(&#39;ROOT&#39;, getcwd().DS);  //当前所在目录 项目目录
 16 define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 17 define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 18 define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 19 define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 20 define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 21 
 22 //MVC目录
 23 define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 24 define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 25 define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.DS.PLAT.DS);
 26 
 27 $ctr = $c."Controller";
 28 
 29 require_once FRAME.&#39;Db.class.php&#39;;  //数据库操作类
 30 require_once FRAME.&#39;BaseModel.class.php&#39;;  //基础模型类
 31 require_once MODEL.&#39;UserModel.class.php&#39;;  //用户模型类
 32 require_once FRAME.&#39;FactoryModel.class.php&#39;;//模型工厂类
 33 require_once FRAME.&#39;BaseController.class.php&#39;; //基础控制器类
 34 require_once CTRONLLER.$ctr.&#39;.class.php&#39;;
 35 
 36 
 37 //实例化控制器
 38 $userCtr = new $ctr();
 39 
 40 $userCtr -> $a();
Copy after login

2) Use of constants:

Background home page controller [App/Controller/Admin/IndexController.class .php】

 1 <?php 
 2 /** 
 3  * IndexController控制器类 
 4  * 后台相关操作 
 5  * User: young 
 6  */ 
 7  
 8 class IndexController extends BaseController 
 9 {
 10     //展示后台首页
 11     public function index()
 12     {
 13         include VIEW.&#39;index.html&#39;;
 14     }
 15 }
Copy after login

Backend home page controller introduction view path modification

User controller login view introduction path【 App/Controller/Home/UserController.class.php】

 1 <?php 
 2 /** 
 3  * UserController.class.php 用户控制器 
 4  */ 
 5  
 6 class UserController  extends  BaseController{ 
 7     /** 
 8      * 展示登录界面 
 9      * @access public
 10      */
 11     public function login()
 12     {
 13         include VIEW."login.html";
 14     }
 15 。。。
 16 。。。
 17 。。。
Copy after login

User controller login view introduction path

3) Submit code

$  git add -A
$  git commit -m "常量使用"
Copy after login

Auto-loading class

Idea

Question: In the entry file 6 classes have been introduced by require_once. If you add one, you need to introduce another one, which is easy to miss, repeat and make mistakes.

Solution: Automatically load class files

Method 1: Use the automatic loading class function __autoload() to achieve automatic loading

Method 2: In actual projects, multiple people develop, according to Practicality, more is to use sql_autoload_register() registration function to automatically load


Implement automatic loading according to the characteristics of the directory

Characteristics of Model class files, class names ending with Model substr($className,-5)

       Controller file features: Class name ending with Controller, substr($class,-10)

​ Public class: There is no unified form of class name, you can put the public classes under Fame into the array, Then determine whether the class is in the array, thereby automatically loading the class file in the directory

Code implementation

1) The entry file implements automatic loading of the class

 1 <?php 
 2 /** 
 3  * 入口文件 
 4  */ 
 5 $p = !empty($_GET[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台 
 6 $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器 
 7 $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作 
 8  
 9 define(&#39;PLAT&#39;, $p);  //平台常量
 10 define(&#39;CTR&#39;, $c);  //控制器
 11 define(&#39;ACTION&#39;, $a); //动作
 12 
 13 
 14 define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 15 define(&#39;ROOT&#39;, getcwd().DS);  //当前所在目录 项目目录
 16 define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 17 define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 18 define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 19 define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 20 define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 21 
 22 //MVC目录
 23 define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 24 define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 25 define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.DS.PLAT.DS);
 26 
 27 $ctr = $c."Controller";
 28 
 29 spl_autoload_register(&#39;autoload&#39;); //注册自动加载函数
 30 //自动加载类
 31 /**
 32  * 实自动加载类文件
 33  * @param  string $className 类名
 34  */
 35 function autoload($className)
 36 {
 37     $upperClassName = strtoupper($className);
 38     $frame = array(&#39;BaseController&#39;,&#39;BaseModel&#39;,&#39;Db&#39;,&#39;FactoryModel&#39;);
 39     if(in_array($className, $frame)) {  //加载公共Frame目录中的类文件
 40         require_once FRAME."$className.class.php";
 41     } elseif(substr($upperClassName, -5) == &#39;MODEL&#39;){  //加载模型Model目录中的类文件
 42         require_once MODEL."$className.class.php";
 43     } elseif(substr($upperClassName, -10) == &#39;CONTROLLER&#39;){  //加载控制器目录中的类文件
 44         require_once CTRONLLER."$className.class.php";
 45     }
 46 }
 47 
 48 //实例化控制器
 49 $userCtr = new $ctr();
 50 $userCtr -> $a();
Copy after login

2) Submit code

1 $  git add -A
2 $  git commit -m "自动加载类完成"
Copy after login

Optimize entry file

Idea

Problem: At this time, the entry file code fragmentation increases. With the increase of subsequent code, the entry file will become more bloated and complex and difficult to manage

Solution: Encapsulate the entry file The operation is called a class, so you only need to call the class method in the entry file

Create the Init.class.php class file and put it into the Frame

Encapsulate all operations of the entry file into classes Method

            loadClass()                                                                                                                                       using   using using           using using ’ ’ ’ s using ’ ’ s ’ through ’ s ’ through ’ s through ‐ to ‐‐‐‐‐ and ​ to

# 1) Create the Init.class.php file in the Frame directory, copy the code in the entry file index and modify it to the class

 [Frame/Init.class.php]

 1 <?php 
 2 /** 
 3  * 应用初始化操作类 
 4  * User: young 
 5  */ 
 6  
 7 class Init 
 8 { 
 9     protected static $frame = array(&#39;BaseController&#39;,&#39;BaseModel&#39;,&#39;Db&#39;,&#39;FactoryModel&#39;); //Frame目录公共操作类
 10     public static function run()
 11     {
 12         //平台
 13         self::dispatch();
 14 
 15         //定义常量
 16         self::setConst();
 17 
 18         //自动加载类
 19         self::loadClass();
 20 
 21         $ctr = CTR."Controller";  //拼接控制器名称
 22 
 23         //实例化控制器
 24         $ctrObj = new $ctr();
 25         $a = ACTION;
 26         $ctrObj -> $a();
 27     }
 28     /**
 29      * 设置自动加载类方法
 30      */
 31     private static function loadClass()
 32     {
 33         spl_autoload_register(&#39;self::autoload&#39;);
 34     }
 35 
 36     /**
 37      * 实现自动加载
 38      * @param  string $className 类名
 39      */
 40     private static function autoload($className)
 41     {
 42         $upperClassName = strtoupper($className);
 43         if(in_array($className, static::$frame)) {
 44             require_once FRAME."$className.class.php";
 45         } elseif(substr($upperClassName, -5) == &#39;MODEL&#39;){
 46             require_once MODEL."$className.class.php";
 47         } elseif(substr($upperClassName, -10) == &#39;CONTROLLER&#39;){
 48             require_once CTRONLLER."$className.class.php";
 49         }
 50     }
 51 
 52     /**
 53      * 定义常量
 54      */
 55     private static function setConst()
 56     {
 57         define(&#39;DS&#39;, DIRECTORY_SEPARATOR); //目录分割符
 58         define(&#39;ROOT&#39;, getcwd().DS);
 59         define(&#39;FRAME&#39;, ROOT.&#39;Frame&#39;.DS);
 60         define(&#39;APP&#39;, ROOT.&#39;App&#39;.DS);
 61         define(&#39;PUB&#39;, ROOT.&#39;Public&#39;.DS);
 62         define(&#39;ADMIN&#39;, PUB.&#39;Admin&#39;.DS);
 63         define(&#39;HOME&#39;, PUB.&#39;Home&#39;.DS);
 64 
 65 
 66         define(&#39;MODEL&#39;, APP.&#39;Model&#39;.DS);
 67         define(&#39;VIEW&#39;, APP.&#39;View&#39;.DS.PLAT.DS.CTR.DS);
 68         define(&#39;CTRONLLER&#39;, APP.&#39;Controller&#39;.DS.PLAT.DS);
 69     }
 70 
 71     /**
 72      * 获取 p c a 的GET值,并设置为常量
 73      * @return void
 74      */
 75     private static function dispatch()
 76     {
 77         $p = !empty($_GET[&#39;p&#39;]) ? $_GET[&#39;p&#39;] : &#39;Home&#39;;  //平台
 78         $c = !empty($_GET[&#39;c&#39;]) ? $_GET[&#39;c&#39;] : &#39;User&#39;;  //控制器
 79         $a = !empty($_GET[&#39;a&#39;]) ? $_GET[&#39;a&#39;] : &#39;login&#39;; //动作
 80 
 81         define(&#39;PLAT&#39;, $p);
 82         define(&#39;CTR&#39;, $c);
 83         define(&#39;ACTION&#39;, $a);
 84     }
 85 }
Copy after login

2) The entry file introduces the initialization class and calls its method [index.php]

1 <?php
2 /**
3  * 入口文件
4  */
5 
6 require_once &#39;./Frame/Init.class.php&#39;;
7 Init::run();
Copy after login

3) Submit code

1 $  git add -A
2 $  git commit -m "优化入口文件,封装初始化类"
Copy after login

安全访问项目目录

  思路

  问题: 此时,项目中所有目录都是可以通过浏览器访问的,如直接访问Frame/Db.class.php文件 直接可以去查看数据库登录信息,显然是不安全的。

  解决方法:

    方式1: 在可以访问的文件开始处定义常量,访问是判断是否定义常量defined(..), 没有定义指定常量则直接exit('Access Deny');

    方式2: 开启分布式权限配置,编写.htaccess文件, 如禁止访问, 将该文件放置在禁止访问的目录中

  实现

  1)使用上述方式2的形式来实现, 站点配置中加入一项(环境搭建时已经加入了): 详细见: PHP源码搭建博客1-环境搭建

  apache配置文件httpd-vhosts.conf 中站点配置

1  #允许分布式权限配置(允许重写)(.htacess)
2   AllowOverride All
Copy after login

  2) 重启apache后,编写 .htaccess文件, 该文件内容:

deny from all
Copy after login

   3) 将.htaccess文件放置禁止访问的目录中。  如App/ ,  Frame/ 目录下。只用放在第一层即可,内层目录自动不允许直接访问。

                               

  4) 访问测试

                   

小结:

主要实现了 引入路径优化, 类的自动加载, 封装优化入口文件,目录访问限制

MVC微型框架到此基本完成。其实还有很多还是可以继续扩展,如

  1, 类文件命名此处都用了 .class.php结尾, 实质可以优化直接使用.php结尾

  2, 引入命名空间,更方便的加载类

       3, 项目中出现错误,此时是直接显示在浏览器上的, 可以写一个日志类,发生错误写入文件或数据库都可

  4, 数据库连接信息此处是直接写在DB类和BaseModel中了, 是不安全的。 可以创建一个配置目录,将这些信息写入配置文件,再写一个加载配置文件的类。

  5.   此架构目录 ,是在C,V中分平台,如Controller/Home, Controller/Admin;  实际也可以写成 平台下分MVC结构, 如Admin/Controller, Admin/Model, Home/Controller,Home/View ..  这个是比较灵活的,可以根据需求选择更加合适的方式

  实际上线项目,还是建议使用框架,安全快捷; 自己模仿定义的框架结构适合学习研究使用,容易遗漏,造成安全隐患,操作不便等问题

下一步:根据博客前端模板,分析创建数据表, 开始搭建博客后台程序,后续首先准备实现 “分类模块”。既分类的展示,修改,添加,删除功能

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

php源码之区分平台MVC结构的介绍

php源码之实现单入口MVC结构的方法

The above is the detailed content of PHP source code to implement MVC structure micro-framework. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template