今天第一次接触到CMS的项目,当时是修改一个别人项目的BUG,说实话,我开始并不了解这是一个开源框架,我开始以为是一个别人字节写的自用框架,而非公共的开源框架。其实本人也写过微框架,本次就借助CMS来谈谈框架的思想。

 框架的本质

     框架的本质,自我理解就是从URL输入到数据处理到数据输出的过程,如果输出的是页面HTML则是传统的MVC模式,如果输出的是JSON的数据集合则是接口模式。如果细分的话,框架本人认为有一下流程。

     框架处理流程: 用户输入URL->rewrite等操作将URL导入到入口文件index.php->预设常量->解析URL生成路由(伪静态实现的地方),从路由中分解出控制器和方法->类的自动载入实现->调用控制器->控制器调用服务->服务调用model->控制器获取数据->控制器包含HTML文件(这一步可以实现页面缓存)->正则匹配将HTML文件中的变量和表达式转换为PHP的语法(前端模板,如blade和smarty)->生成纯HTML页面->返回给浏览器->浏览器渲染

框架生命流程

一. 第一步,用户输入URL

     1. 格式1:http://www.jianzhu.com/index.php/index/index?a=1&b=3http://www.jianzhu.com/index/index?a=1&b=3

      2.格式2:http://www.jianzhu.com/index.php?m=Index&a=hello&param1=1&param2=2

       第二种格式比较简单,获取所有的参数,URL2中的?后的参数通过GET传输,会放置在GET全局参数变量中,从GET['m']和$_GET['a']获取参数,并认为m是控制器,如m=index,a=hello则表示IndexController控制器的hello方法。参数为param1和param2。这样很容易解析成路由,但无法再方法中注入参数,不在本次的讨论范围之内。本文只讨论第一种样式

三.将路由转到入口文件index.php

          该入口文件一般放在服务器设定的项目根目录中的public文件下,通常是index.php。路由http://www.jianzhu.com/index/index?a=1&b=3,此种路由没有显示导入index.php,可以使用apache的.htacess转写RewriteRule ^(.*)$ index.php/$1 [L],或者nginx的try_file转写到http://www.jianzhu.com/index.php/index/index?a=1&b=3路由,这样就进入了入口文件,此种做法也叫路径优化,让index.php变得不可见,当然你显示输入路径也是OK的。

四.预设常量

这里一般会预设一些常量和全局配置操作,以CMS举例,在入口文件中预设了基本的路径和配置了utf8编码

     1. 预设路径常量

        

cms架构发布 cms架构图_cms架构发布

 2. 加载配置

    

cms架构发布 cms架构图_php_02

3. 调用核心框架文件

该文件在LARAVEL中式实例化了一个容器对象,在CMS中是实例化了一个cpApp文件,由于此时尚未写PHP自动载入函数,一般该自动载入函数写在基础容器对象中。所以在new出容器对象的时候,要显示引入cpApp.class.php文件

cms架构发布 cms架构图_框架解析_03

   

cms架构发布 cms架构图_cms架构发布_04

     注意:涉及到的路径的服务器常量

     以http://www.jianzhu.com/index.php/index/index?a=1&b=3举例    

其中要注意的的变量是

     QUERY_STRING:查询字符串,即问号'?'之后的字符串

     SCRIPT_NAME:脚本名字,即入口脚本的名字为index.php

     PHP_SELF:即端口后的,问号之前的路径,要和SCRIPT_NAME相互区分

     REQUEST_URI:全路径,即端口后面的所有路径,包含问号后的参数

     PATH_INFO :即问好之前端口之后,取出掉SCRIPT_NAME的路径   

cms架构发布 cms架构图_CMS_05

好了,现在我们总结下,CMS的入口文件都干了什么

cms架构发布 cms架构图_CMS_06

 

cms架构发布 cms架构图_cms架构发布_07

 

cms架构发布 cms架构图_php_08

1行设置了编码方式为utf-8,

2行设置了时区

4-13行获取去除参数的路径REQUEST_URI,即端口后,问号前的内容

16行定义核心框架目录

17行引入了框架的核心处理类

21到34行,将路由中的语言方式解析出来,术语叫国际化即可以编写中文版本和英文版本的文字。处理的方式是将语言的标识写在REUQEST_URI中,然后再语言目录中匹配

cms架构发布 cms架构图_cms架构发布_09

如果是中文就取中文zh下面的配置,该配置控制某些按钮或者文档的显示,如果是英文获取英文的配置,配置如下

cms架构发布 cms架构图_缓存_10

,如果匹配到了,然后将语言标识从REQUEST_URI中替换掉,则现在的REQUEST_URI中午语言标识了。

35行定义匹配到的语言常量,可能是英文也可能是中文

38到46行定义手机常量

48-49行设置自定义目录,其实如果我写肯定不这么写,我可以在这里定义根目录为顶层文件夹的目录

58-60行实例化了容器对象cpApp,初始化了语言及配置,然后运行了容器对象的run方法。

 

五,解析URL生成控制器和方法

    现在我们进入容器类cpApp类,我们可以看到,其首先定义了模块和名称的静态变量,本质是为了解析出控制器和相应的方法,

cms架构发布 cms架构图_框架解析_11

然后到了构造函数,在构造函数中定义了一些常量和设置了配置信息

cms架构发布 cms架构图_cms架构发布_12

 

从13行中我们可以看到该CMS有个默认配置文件,该文件cpConfig.php设置了APP,DB和模板TPL的默认配置,然后将这些配置塞到静态数组中,并定义了GET和SET方法来获取这些参数。这里巧妙的应用了array_merge来覆盖配置,即如果用户在配置文件cpConfig.class.php文件中配置了自定义配置,则会覆盖了系统的默认配置。

cms架构发布 cms架构图_cms架构发布_13

该控制器中有个自动加载函数

cms架构发布 cms架构图_缓存_14

可以从中看出,本核心类中实现了自己的自动加载算法,28到35行是引入了一些系统内置处理函数。怎么样有没有像LARAVEL的bootstap文件中干的内容。看看自动加载的写法

cms架构发布 cms架构图_框架解析_15

可以看出,这里其实很简单,将几个大文件夹中的路径的文件全部引入进来。并且这些文件都以类名+".class.php"组合而成,这种写法其实很low没有用到命名空间,而且PSR的写法是配置一个顶层的命名空间对应的目录,然后后续的目录和剩下的命名空间对应,然后类文件是以类名+'.php'的形式命名的。从中可以看出这个CMS版本是很老的,而且命名也不遵守PSR规范。

我们接着看run函数都干了什么

cms架构发布 cms架构图_CMS_16

     

cms架构发布 cms架构图_CMS_17

这个方法究竟干了什么呢,从中我们知道干了以下的事情

43到54行是解析出来了路由,并将路由塞到GET全局数组中,如果路由不存在就使用默认路由,这个就是从REQUEST_URI中按照一定规则解析出控制器、方法和参数,由于实现比较简单,这里就不描述了

cms架构发布 cms架构图_框架解析_18

 

cms架构发布 cms架构图_cms架构发布_19

cms架构发布 cms架构图_CMS_20

这里没什么好说的,唯一可以说的是伪静态的处理方式,这里可以看出90到111行就是从完整的REQUEST_URI包含了?后面的参数中去除了后面的参数,并将其变成参数,然后去除了脚本文件大部分是index.php获取了不包含参数和脚本路径的纯路径,在这个纯路径的最后会加入一些如.HTML的标识,用以迷惑用户,以让其认为这是个静态文件,例如这里的路由http://www.jianzhu.com/index.php/index/index.html?a=1&b=3,最后的index.html中的.html是伪静态标识在纯路径的最后,是可以配置的,其实本质是indexController的index方法,在解析路由的时候用了增加一个后缀的小技巧,就生成了伪静态,可以看出这里处理伪静态的方法是在路由解析中实现的。

56到59行加载了初始化程序

61行预定义了一些常量

64到70行 查看了控制器module是否存在,即控制器是否存在

73到75行读取该控制器该方法的缓存,如果没有缓存则执行该控制器的方法excute

78行然后调动结束前的回调函数。

由于这里内容很多,这里就讲excute方法,里面就是判断了下控制器存不存在,方法存不存在,如果存在就调用该控制器的该方法,如果开启了缓存,则将该方法生成的页面转换为缓存页面。实现比较简单这里就不描述了

cms架构发布 cms架构图_php_21

这里将读入写入缓存的操作单独分出了一个缓存类来实现。类名cpHtmlCache用该类来读写缓存,具体内容参见CMS的该类

该类功能概括下就是,将方法获取的内容写入到缓存文件中,取得时候从缓存文件中取,可以清空删除缓存文件,在取的时候通过缓存文件的创建时间和当前时间来判断缓存文件有无过期。

今天就讲到这里,剩下的就是CMS调用数据model类的实现了,这个后续再谈。