目錄
常數最佳化路徑
  思路" >  思路
  程式碼實作" >  程式碼實作
" >   想法
" >  程式碼實作
安全访问项目目录
   思路" >   思路
   实现" >   实现
小结:
首頁 後端開發 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()可以實現自動載入

          實用性,更多的是使用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() 自動         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

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

會話如何劫持工作,如何在PHP中減輕它? 會話如何劫持工作,如何在PHP中減輕它? Apr 06, 2025 am 12:02 AM

會話劫持可以通過以下步驟實現:1.獲取會話ID,2.使用會話ID,3.保持會話活躍。在PHP中防範會話劫持的方法包括:1.使用session_regenerate_id()函數重新生成會話ID,2.通過數據庫存儲會話數據,3.確保所有會話數據通過HTTPS傳輸。

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

在PHPStorm中如何進行CLI模式的調試? 在PHPStorm中如何進行CLI模式的調試? Apr 01, 2025 pm 02:57 PM

在PHPStorm中如何進行CLI模式的調試?在使用PHPStorm進行開發時,有時我們需要在命令行界面(CLI)模式下調試PHP�...

描述紮實的原則及其如何應用於PHP的開發。 描述紮實的原則及其如何應用於PHP的開發。 Apr 03, 2025 am 12:04 AM

SOLID原則在PHP開發中的應用包括:1.單一職責原則(SRP):每個類只負責一個功能。 2.開閉原則(OCP):通過擴展而非修改實現變化。 3.里氏替換原則(LSP):子類可替換基類而不影響程序正確性。 4.接口隔離原則(ISP):使用細粒度接口避免依賴不使用的方法。 5.依賴倒置原則(DIP):高低層次模塊都依賴於抽象,通過依賴注入實現。

如何在系統重啟後自動設置unixsocket的權限? 如何在系統重啟後自動設置unixsocket的權限? Mar 31, 2025 pm 11:54 PM

如何在系統重啟後自動設置unixsocket的權限每次系統重啟後,我們都需要執行以下命令來修改unixsocket的權限:sudo...

如何用PHP的cURL庫發送包含JSON數據的POST請求? 如何用PHP的cURL庫發送包含JSON數據的POST請求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL庫發送JSON數據在PHP開發中,經常需要與外部API進行交互,其中一種常見的方式是使用cURL庫發送POST�...

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

See all articles