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

一步步编写PHP的Framework(十)

之前讲了这么多,实际上都只是为框架搭建了一个架子而已,框架里面还没有什么东西,从今天开始,我就开始从Controller,Model,View这几块儿来分别介绍一下。PS:之前的很多内容我都没有细讲,就比如路由,真正...">

 

之前讲了这么多,实际上都只是为框架搭建了一个架子而已,框架里面还没有什么东西, 从今天开始,我就开始从Controller,Model,View这几块儿来分别介绍一下。

PS:之前的很多内容我都没有细讲,就比如路由,真正的框架路由肯定不是通过GET方式指定的,而是正则,并且它需要兼容多个Server,多种方式。

我们知道所有的请求都需要经过控制器,所以首先还是说一下控制器。

我们之前已经 说过控制器的概念了,但是这个控制器还是功能太弱了,因为它只是从功能上是控制器,框架并没有为它做任何事情,框架实际上可以实现一些常用的功能,然后用户定义的控制器继承它,这样用户可以少写很多代码的。

之前的控制器是:

1
2 class IndexController {
3     public function index() {
4         echo 'Hello world';
5     }
6 }

现在假设框架已经实现了控制器的一些基本功能,这个类我们称为Controller.php,那么现在代码就变成了:

1
2 class IndexController extends Controller {
3     public function index() {
4         echo 'Hello world';
5     }
6 }

这样做有什么好处呢,由于Controller继承了Base,所以IndexController也拥有了Base的功能,这样就不需要用户再编写很多捕获的代码等。

 

当然,这样做也有缺点,测试IndexController的时候比较麻烦。

今天我先说一下控制器比较基础的两个功能,跳转和转发。

首先是跳转,这个用的太普遍了,比如用户登录的时候,点击登录按钮,进入后台处理的页面,处理完毕之后就需要跳转,那么怎么实现跳转呢?

有几种方式:

           第一种:在JS中实现跳转;

           第二种:header("Location:url");具体使用可查看PHP手册;

           第三种:在HTML的meta中设置refresh;

由于header调用的时候如果之前页面已经有输出,跳转会失效,所以需要结合meta的refresh一起使用,当然,你也可以直接使用JS的这种方式来实现,只是我不太喜欢这种方式,因为我之前使用这种方式实现跳转的时候出过问题。

现在我们定义跳转这个函数的名字为_redirect,为什么前面加上_呢,这也是我的一个习惯,对于函数,只要不是public,我都使用_作为前缀。可能大家会问了,为什么不设置这个函数为public呢,因为用户编写的控制器也只会继承它而不会直接调用,所以我设置成为了protected。      

1 protected function _redirect(Array $arr) {
2  
3  
4 }

 

暂时可以将功能弄得弱一点,假设跳转的参数通过数组传递过来,那么我们可以使用类型提示(Array $arr)这种方式来搞定,如果传递的参数不是数组,那么直接会报错。

我们使用的方式可以是这样:

1 $this->_redirect(array(
2         'action' => 'test',
3         'controller' => 'Test',
4         'param1' => '1'
5 ));

 

它代表的意思是跳转到Test这个控制器的test这个Action,并且还传递了一个参数,这个参数名为param1,值为1。

01 protected function _redirect(Array $arr) {
02         $cOntroller= empty($_GET['c']) ? C('defaultController') : trim($_GET['c']); //设置了默认的控制器
03         $action= empty($_GET['a']) ? C('defaultAction') : trim($_GET['a']); //设置了默认的Action
04         array_key_exists('controller',$arr) || $arr['controller'] = $controller;
05         array_key_exists('action',$arr) || $arr['action'] = $action;
06         $str = '/?';
07         foreach($arr as $key => $val) {
08             if(!is_int($key)) {
09                 $str .= ($key . '=' . $val . '&');
10             }
11         }
12         $str = substr($str,0,strlen($str) - 1);
13         Response::redirect($str);
14     }

 

这个就是我刚刚手写的跳转代码,实际上就是把传递的数组拼接一下然后组成一个字符串,这个字符串就可以看成是一个URL,由于现在没有对Route.php进行更多的处理,对于localhost/demo2/index.php?cOntroller=a这种URL它跳转就会出错,暂时只支持localhost/index.php?cOntroller=a这种URL,还有$controller和$action的获取和Route.php中的代码重复了,这些都需要在后面真正实现路由的时候再讲解,暂时就这么看看吧,虽然我自己都感觉这样的代码很恶心。

可能大家都注意到了,当这个函数拼接到URL之后,是直接调用了Response的redirect方法,这是为什么呢?

第一:有可能在真正应用中,我们直接在控制器中调用$this->_redirect满足不了我们的需求,这个时候我们就需要直接调用Response::redirect,比如跳转到百度首页就只能调用Response::redirect("http://www.baidu.com");

第二:从逻辑上,跳转是一个服务器对客户端的响应,所以需要写在Response中,具体的可参照Java。

那么我们又必须新建一个Response.php这样一个文件:

01
02 class Response extends Base {
03     public static function redirect($url) {
04         if(is_string($url)) {
05             if(!headers_sent()) {
06                 header("Location:" . $url);
07                 exit();
08             } else {
09                 $str = '';
10                 exit($str);
11             }
12         } else {
13             //错误处理
14         }
15     }
16 }

这里的逻辑比较简单,实际上就是判定是否有输出,没有输出那么就直接使用header("Location")进行跳转,如果有输出,那么使用meta的refresh跳转。

 

注意:实际上还可以在这个跳转上开发更多的功能,但是由于我只是大概讲一下,所以更多的内容就不写了,有兴趣的人可以去Toper上面看看。

这样,一个比较简单的跳转就完成了,那么怎么实现转发呢?

可以简单这样理解,转发实际上就是再调用了一下某一个Controller的某一个Action。

所以这样我们就可以比较简单的实现转发了:

01 protected function _forward(Array $arr) {
02         $cOntroller= empty($_GET['c']) ? C('defaultController') : trim($_GET['c']); //设置了默认的控制器
03         $action= empty($_GET['a']) ? C('defaultAction') : trim($_GET['a']); //设置了默认的Action
04         if(array_key_exists('controller',$arr)) {
05             $controller = $arr['controller'];
06         }
07         if(array_key_exists('action',$arr)) {
08             $action = $arr['action'];
09         }
10         $controller .= 'Controller';
11         if($controller === get_class()) {
12             if(method_exists($this,$action)) {
13                 $this->$action();
14             } else {
15                 //时间有限,不写逻辑了
16             }
17         } else {
18             if(class_exists($controller)) {
19                 $class = new $controller();
20                 if(method_exists($class,$action)) {
21                     $class->$action();
22                 } else {
23                     //时间有限,不写了
24                 }
25             } else {
26                 //时间有限,不写了
27             }
28         }
29     }

实际上逻辑上就是判定一下要调用的Action是否属于本控制器,如果是本控制器,直接调用$this->$action()即可,否则,需要实例化这个控制器,即$class = new $controller(),然后再调用这个Action。

本来以为半个小时就可以写完,结果写了一个小时了,由于时间超出我的预算,所以代码都是手写的,不知道有不有什么语法错误什么的,反正看看思路就OK了。


推荐阅读
  • PHP图床源码:集成化图床管理系统解决方案
    本项目提供了一套集成化的图床管理系统解决方案,适用于需要高效管理图片资源的场景。系统结构简洁,无需复杂的后台支持。主要文件包括 `huluxia.php`、`index.html`、`inews.php`、`kw.php` 和 `zz.php`,每个文件都承担了特定的功能,确保系统的稳定运行和易用性。 ... [详细]
  • 业务背景:为了规范22毫米配置的采购信息记录,需明确其编码范围。通过事务码OMEO,在物料管理模块下的采购子模块中,具体路径为“物料管理-采购-采购信息记录-定义编码范围”,进行编码范围的定义。首先,需进入SPRO系统进行相关设置。此步骤确保了采购信息记录的标准化与可追溯性,提高了供应链管理的效率。 ... [详细]
  • 本文深入探讨了原型模式在软件设计中的应用与实现。原型模式通过使用已有的实例作为原型来创建新对象,而不是直接通过类实例化。这种方式不仅简化了对象的创建过程,还提高了系统的灵活性和效率。具体来说,原型模式涉及一个支持克隆功能的接口或基类,子类通过实现该接口来提供具体的克隆方法,从而实现对象的快速复制。此外,文章还详细分析了原型模式的优缺点及其在实际项目中的应用场景,为开发者提供了实用的指导和建议。 ... [详细]
  • 本文详细探讨了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` 组件,详细说明它们在应用中的作用和交互方式。通过这些组件的协同工作,我们将展示如何构建一个高效且响应迅速的笔记本应用。 ... [详细]
  • Photoshop教程第五讲:使用套索工具精准抠图技巧
    在本节Photoshop教程中,我们将深入探讨如何利用套索工具实现精准的图像抠图。通过详细的操作步骤和实用技巧,帮助用户掌握套索工具的多种使用方法,提升图像处理的精细度和效率。 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
author-avatar
情深深锋_433
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有