搜索
首页后端开发php教程php源码之实现MVC结构微型框架

php源码之实现MVC结构微型框架

Jul 05, 2018 am 09:53 AM
php源码

这篇文章主要介绍了关于php源码之实现MVC结构微型框架,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

主要:

  1. 常量优化路径

  2. 自动加载类

  3. 优化入口文件

  4. 安全访问项目目录


----------------------------------------------------
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  入口文件
-----------------------------------------------------------------


上一篇中,提出4个问题待解决,本篇集中解决这4个问题,最终形成完整的微型MVC框架结构, 后续博客项目,或其他项目,均可以直接使用该框架结构进行开发学习。

下载查看该项目源码: https://gitee.com/NewbiesYang/young_blog

常量优化路径

准备: 创建分支

1 $ git checkout master
2 $ git checkout -b "MVC"

  思路

  1)把常用的目录路径定义成常量。如 模型目录,控制器目录等
     2)引入类使用定义的常量替代部分路径。 如 include FRAME.BaseModel.class.php
       3) 载入视图使用常量替代部分路径 如 include VIEW.'login.html' 简单形式

  代码实现

 1)操作步骤

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

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

操作步骤思路

  2) 入口文件中定义常用路径常量 【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();

2) 常量的使用:

  后台首页控制器【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 }

后台首页控制器引入视图路径修改

  用户控制器 登录视图引入路径【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 。。。

用户控制器登录视图引入路径

3)提交代码

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

自动加载类

   思路

  问题: 入口文件中已经require_once 引入6个类,既增加一个需要引入一个,容易遗漏,重复和出错。

  解决方法:自动加载类文件

     方式1: 使用自动加载类函数__autoload()可以实现自动加载
          方式2: 实际项目中,多人开发,根据实用性,更多的是使用 sql_autoload_register()注册函数自动加载

  根据目录的特点实现自动加载
          Model类文件特点,以Model结尾的类名  substr($className,-5)
          Controller文件特点: 以Controller结尾的类名, substr($class,-10)

    公共类: 类名没有统一形式,可以将Fame下的公共类放入到数组中,然后判断类是否在数组中, 从而自动加载该目录下的类文件

  代码实现

   1) 入口文件实现类的自动加载

 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();

2) 提交代码

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

优化入口文件

  思路

  问题: 此时,入口文件代码零碎增多,随着后续代码的增加,入口文件会更加臃肿复杂,不易管理

  解决方法: 封装入口文件中的操作称为一个类,这样只需要在入口文件调用类的方法即可

    创建Init.class.php类文件,放入到Frame中
         将入口文件所有操作封装成类方法
              loadClass() 设置自动加载函数
              autoload()自动加载类
              setConst()  定义常量
              dispatch()  前端分发器

  代码实现

   1) 在Frame目录中创建Init.class.php文件, 将入口文件index中的代码复制进行修改为类

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

2) 入口文件引入初始化类,并调用其方法 【index.php】

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

3) 提交代码

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

安全访问项目目录

   思路

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

  解决方法:

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

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

   实现

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

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

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

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

deny from all

   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结构的方法

以上是php源码之实现MVC结构微型框架的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
继续使用PHP:耐力的原因继续使用PHP:耐力的原因Apr 19, 2025 am 12:23 AM

PHP仍然流行的原因是其易用性、灵活性和强大的生态系统。1)易用性和简单语法使其成为初学者的首选。2)与web开发紧密结合,处理HTTP请求和数据库交互出色。3)庞大的生态系统提供了丰富的工具和库。4)活跃的社区和开源性质使其适应新需求和技术趋势。

PHP和Python:探索他们的相似性和差异PHP和Python:探索他们的相似性和差异Apr 19, 2025 am 12:21 AM

PHP和Python都是高层次的编程语言,广泛应用于Web开发、数据处理和自动化任务。1.PHP常用于构建动态网站和内容管理系统,而Python常用于构建Web框架和数据科学。2.PHP使用echo输出内容,Python使用print。3.两者都支持面向对象编程,但语法和关键字不同。4.PHP支持弱类型转换,Python则更严格。5.PHP性能优化包括使用OPcache和异步编程,Python则使用cProfile和异步编程。

PHP和Python:解释了不同的范例PHP和Python:解释了不同的范例Apr 18, 2025 am 12:26 AM

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

PHP和Python:深入了解他们的历史PHP和Python:深入了解他们的历史Apr 18, 2025 am 12:25 AM

PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

在PHP和Python之间进行选择:指南在PHP和Python之间进行选择:指南Apr 18, 2025 am 12:24 AM

PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

PHP和框架:现代化语言PHP和框架:现代化语言Apr 18, 2025 am 12:14 AM

PHP在现代化进程中仍然重要,因为它支持大量网站和应用,并通过框架适应开发需求。1.PHP7提升了性能并引入了新功能。2.现代框架如Laravel、Symfony和CodeIgniter简化开发,提高代码质量。3.性能优化和最佳实践进一步提升应用效率。

PHP的影响:网络开发及以后PHP的影响:网络开发及以后Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?Apr 17, 2025 am 12:25 AM

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能