当前位置:  开发笔记 > 编程语言 > 正文

一步步编写PHP的Framework(七)

之前我们在入口文件就直接调用了Route::run(),这样做有不有什么问题呢?答案是有的!有时候在进行路由之前和之后需要进行一些额外的处理,如果按照之前在入口文件直接调用Route::run()的话,那么这些处理过程只...">

 

之前我们在入口文件就直接调用了Route::run(),这样做有不有什么问题呢?

答案是有的!

有时候在进行路由之前和之后需要进行一些额外的处理,如果按照之前在入口文件直接调用Route::run()的话,那么这些处理过程只能写在入口文件中,但是入口文件本不应该做这样的事情,那么我们该怎么样来解决这个问题呢?

我们引入一个前端控制器的概念,它相当于一个总控,所有外部的请求都在它的控制范围内,那么这些额外的处理是不是就可以放在这个控制器中了呢!!

好,我们现在先修改一下入口文件:

01
02 defined('APP_PATH') || define('APP_PATH',dirname(__FILE__) . '/..');
03 defined('FRAMEWORK_PATH') || define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
04 defined('MODULES_PATH') || define('MODULES_PATH',APP_PATH . '/UserApps/Modules');
05 defined('CONFIGS_PATH') || define('CONFIGS_PATH',APP_PATH . '/UserApps/Configs');
06 include FRAMEWORK_PATH . '/function.php';
07 C(Config::factory(Config::PHP)); //写入配置信息
08 include FRAMEWORK_PATH . '/FrontController.php';
09 $frontController = FrontController::getInstance();
10 $frontController->run();

 

这段代码实际上修改的内容不多,也就修改了:

1 include FRAMEWORK_PATH . '/FrontController.php';
2 $frontController = FrontController::getInstance();
3 $frontController->run();

这段代码首先include了前端控制器这个文件,然后实例化了前端控制器,然后调用前端控制器这个类的run方法。

为什么不直接使用$frOntController= new FrontController()?

如果你把握后面的代码下载后运行会发现,这样会报错,为什么呢?

这儿我需要介绍另外一个概念:单例模式。

单例模式就是在整个程序运行过程中只有一个实例,比如数据库的连接,即使有很多类,但是可能这些类都公用数据库的连接,那么数据库的连接就是单例的。

为什么要使用单例呢?

大家可以想一下,前端控制器控制整个程序的运行,那么它的确是不应该有多份的,是不是?

 为了保证是单例的,所以我们一般使用一个静态方法(getInstance)来实例化它,为了防止用户直接new和克隆一个对象,我们需要将__construct和__clone设置为私有。

01
02 class Test {
03     private static $_instance = null;
04     private function __construct() {}
05     private function __clone() {}
06     public static function getInstance() {
07         if(null === self::$_instance) {
08             self::$_instance = new Test();
09             echo '1';
10         }
11         return self::$_instance;
12     }
13 }
14  
15 $test = Test::getInstance();
16 $test2 = Test::getInstance();

 

如果执行这段代码,会发现只输出了一个1,说明实例化只执行了一次。

说了这么多,大家应该都应该懂了吧,那就直接贴出前端控制器的代码吧:

01
02 class FrontController {
03     private static $_instance = null;
04     private function __construct() {}
05     private function __clone() {}
06     public static function getInstance() {
07         if(!(self::$_instance instanceof self)) {
08             self::$_instance = new FrontController();
09         }
10         return self::$_instance;
11     }
12     public function run() {
13         Route::run();
14     }
15 }

当然,前端控制器中我是使用了instanceof来判定的,其实也可以直接用null === self::$_instance来判定。

 

这段代码很简单,实际上就把Route::run()转移到FrontController了,其他的都没有什么变化。

大家可能注意到了,入口文件的内容还是太多了,为什么不能把入口文件的东西迁移到FrontController呢,那么那些可以迁移到FrontController呢,首先是定义的常量,其实只要用户定义APP_PATH即可,其他的常量都可以由框架默认,其次是配置文件的写入,这种内容框架完全可以自己搞定,所以,入口文件的代码变成了这样:

1
2 defined('APP_PATH') || define('APP_PATH',dirname(__FILE__) . '/..');
3 defined('FRAMEWORK_PATH') || define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
4 include FRAMEWORK_PATH . '/FrontController.php';
5 $frontController = FrontController::getInstance();
6 $frontController->run();

我在此处留下了FRAMEWORK_PATH,是因为我要引用框架的文件,其实也不定义FRMAEWORK_PATH,而改用include APP_PATH . '/Library/Test/FrontController.php'。

 

同样,FrontController的代码也发生了变化:

01
02 defined('APP_PATH') || exit('未定义APP_PATH');
03 defined('FRAMEWORK_PATH') || define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
04 defined('MODULES_PATH') || define('MODULES_PATH',APP_PATH . '/UserApps/Modules');
05 defined('CONFIGS_PATH') || define('CONFIGS_PATH',APP_PATH . '/UserApps/Configs');
06 include FRAMEWORK_PATH . '/function.php';
07 class FrontController {
08     private static $_instance = null;
09     private function __construct() {
10         C(Config::factory(Config::PHP)); //写入配置信息
11     }
12     private function __clone() {}
13     public static function getInstance() {
14         if(!(self::$_instance instanceof self)) {
15             self::$_instance = new FrontController();
16         }
17         return self::$_instance;
18     }
19     public function run() {
20         Route::run();
21     }
22 }

首先,这个文件判定是否定义了APP_PATH,由于这个常量非常重要,其他路径都依靠它,所以用户如果不指定,程序就需要停止。其他的常量如果没有定义,那么就定义它,这个很简单。

 配置文件写到了构造函数中了,因为不管getInstance调用多少次,构造函数只会被调用1次,而配置文件刚好也只需要写入一次。


推荐阅读
  • 如何在PHP中提取数字的特定位数值
    本文将详细介绍如何在PHP中提取数字的特定位置的数值。这一技巧对于数据处理和算法实现具有重要意义,通过实例代码和详细解析,帮助读者掌握该方法的应用场景和实现方式。 ... [详细]
  • 本文深入探讨了 iOS 开发中 `int`、`NSInteger`、`NSUInteger` 和 `NSNumber` 的应用与区别。首先,我们将详细介绍 `NSNumber` 类型,该类用于封装基本数据类型,如整数、浮点数等,使其能够在 Objective-C 的集合类中使用。通过分析这些类型的特性和应用场景,帮助开发者更好地理解和选择合适的数据类型,提高代码的健壮性和可维护性。苹果官方文档提供了更多详细信息,可供进一步参考。 ... [详细]
  • 在Linux环境下,本文详细探讨了Apache服务器中CGI技术的应用与实现。首先,通过使用yum包管理器安装了必要的软件,如PHP。安装完成后,对Apache服务器进行了配置,确保CGI功能正常运行。此外,还介绍了如何编写和调试CGI脚本,以及如何在实际环境中部署这些脚本以提供动态网页内容。实验结果表明,通过合理的配置和优化,Apache服务器能够高效地支持CGI应用程序,为用户提供丰富的交互体验。 ... [详细]
  • 深入解析 Django 中用户模型的自定义方法与技巧 ... [详细]
  • 本文深入探讨了原型模式在软件设计中的应用与实现。原型模式通过使用已有的实例作为原型来创建新对象,而不是直接通过类实例化。这种方式不仅简化了对象的创建过程,还提高了系统的灵活性和效率。具体来说,原型模式涉及一个支持克隆功能的接口或基类,子类通过实现该接口来提供具体的克隆方法,从而实现对象的快速复制。此外,文章还详细分析了原型模式的优缺点及其在实际项目中的应用场景,为开发者提供了实用的指导和建议。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • 美国血统争议与遗传学研究进展:在遗传学领域,血统记录的准确性至关重要。然而,在实际操作中,记录错误时有发生。本文探讨了通过遗传学方法验证血统的有效性,并介绍了利用二叉树结构进行家谱分析的技术,特别是中序遍历和前序遍历的应用,为血统争议提供科学依据。 ... [详细]
  • 扎克伯格透露:一种新型类皮肤材料可能加速“元宇宙”愿景实现
    Meta公司的人工智能团队与卡内基梅隆大学的科学家合作,开发出了一种厚度不足3毫米的可变形塑料材料,这种低成本的“皮肤”有望加速“元宇宙”愿景的实现。该材料具有高度的灵活性和响应性,能够模拟真实皮肤的触感,为虚拟现实和增强现实技术提供更加沉浸式的体验。 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • Web自动化测试:表单提交与页面跳转的高效实现
    Web自动化测试:表单提交与页面跳转的高效实现 ... [详细]
  • Issue with the Reserved Term HOSTS in System Configuration ... [详细]
  • 题目描述非常吸引人。每颗星星可以通过其在窗口的左下角和右上角位置构建两条扫描线,从而将问题转化为区间增减和求最大值的操作。需要注意的是,位于边界的星星不应计入结果,因此在处理时应分别对左右边界进行适当的增减调整。此外,利用线段树和离散化技术可以显著提高算法效率,确保在大规模数据下的性能表现。 ... [详细]
  • 本文探讨了如何在C#中实现USB条形码扫描仪的数据读取,并自动过滤掉键盘输入,即使不知道设备的供应商ID(VID)和产品ID(PID)。通过详细的技术指导和代码示例,展示了如何高效地处理条形码数据,确保系统能够准确识别并忽略来自键盘的干扰信号。该方法适用于多种USB条形码扫描仪,无需额外配置设备信息。 ... [详细]
  • 在《PHP应用性能优化实战指南:从理论到实践的全面解析》一文中,作者分享了一次实际的PHP应用优化经验。文章回顾了先前进行的一次优化项目,指出即使系统运行时间较长后出现的各种问题和性能瓶颈,通过采用一些通用的优化策略仍然能够有效解决。文中不仅详细阐述了优化的具体步骤和方法,还结合实例分析了优化前后的性能对比,为读者提供了宝贵的参考和借鉴。 ... [详细]
  • Vuex 实战进阶:构建高效笔记本应用(第二篇)
    在上一篇文章中,我们初步探讨了 Vuex 在该项目中的应用。本文将深入解析整个项目的架构设计。首先回顾 `main.js` 的内容,然后重点分析 `App.vue` 文件,其中引入了 `Toolbar.vue` 和 `NodeList.vue` 组件,详细说明它们在应用中的作用和交互方式。通过这些组件的协同工作,我们将展示如何构建一个高效且响应迅速的笔记本应用。 ... [详细]
author-avatar
gu油漆装修
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有