前言
写这篇文章的初衷,是因为群里因为一个美女工程师而引发了一阵骚动,作为一个看到美女就眼睛放光的人来说,怎么会放过这么好欣赏美女的机会[色]。于是大家将美女的github给翻出来了,我有幸看到了美女写的php框架,download下来,认真向美女学习[崇拜ing]。
美女的框架前言是这样:
写此框架的初衷是因为发现现在流行的php框架都异常臃肿,臃肿的原因是因为框架都封装了许多的功能,这些功能我在实际开发中很多并未使用到,这就造成使用框架的性能浪费。
基于此,于2014年的五一期间写了这个框架,众多流行框架都有一个自己的名字,我就为这个框架取名叫“one”。
刚开始参加工作的时候,因为技术基础很烂,所以被分配到去做管理平台的网页。那时候被同事问及知道什么是MVC吗,我说听过,不知道确切的MVC是什么。于是同事介绍哪里写哪一部分,哪里负责什么功能,什么部分该写在什么部分。第一次就是简单在index.html添加一个菜单,通过这个菜单跳转到某一个页面。
此框架虽然简单,但是其提取出来了核心骨架,虽然不适合真正去建立大型网站,但是适合初学者去了解MVC以及网站的基本搭建。
代码范例
一个美女的简单的PHP框架one---- https://github.com/linsunny/one
想要鉴定美女的童鞋,可以发挥自己的想象力网上百度下。
代码架构
框架的架构如下图所示,library文件夹保存的是核心类,也就是一些基类,比如model,view,controller的基类,mysql的sql操作类,启动框架逻辑,统筹全局的core类。index.php作为入口文件,view存储的主要为视图文件,如html,或者是smarty的tpl文件,st为静态文件,比如js,css,image等。model保存的是业务逻辑处理代码文件,负责处理用户请求,保存用户数据到db,cache,以及访问db,cache读取用户数据等。controller保存的是负责接收用户请求,并调用model处理用户请求,并将用户请求结果在view中显示。配置文件保存的是各种资源(db,smarty,router等)的相关配置。
后续会在代码中体现这些文件是如何各司其责的。
本部分将通过分析在浏览器输入一个url链接到页面显示的整个过程,了解本框架的数据流。
在本机上部署好xmapp环境后,将代码放到/var/www/html/目录下
url: http://beauty/one-branch/index.php?c=index&a=init
在浏览器中输入如上链接,点击enter,可以看到如下的页面。
附上页面显示
数据流
- 域名解析服务器ip和port
如在浏览器中输入网址:http://beauty/one-branch/index.php?c=index&a=init
- 通过web服务器找到相应的代码路径
http解析上面的网址,域名beauty解析到服务器172.16.0.0:80,然后在172.16.0.0这台服务器上的apache的配置文件(如下截图所示)将根据port,找到根目录路径DocumentRoot。即将http://beauty映射到172.16.0.0的目录/var/www/html下,从而将
http://beauty/one-branch/index.php?c=index&a=init 映射到 var/www/html/one-branch/index.php?c=index&a=init
配置文件的截图如下:
附上apache配置
index.php的代码如下:
<?php define(‘ROOT_PATH‘, dirname(__FILE__) . DIRECTORY_SEPARATOR ); define(‘CONTROLLER_PATH‘, ROOT_PATH . ‘controller‘ . DIRECTORY_SEPARATOR); define("VIEW_PATH", ROOT_PATH ."view" . DIRECTORY_SEPARATOR); define("CACHE_PATH", ROOT_PATH ."cache" . DIRECTORY_SEPARATOR); define("MODEL_PATH", ROOT_PATH ."model" . DIRECTORY_SEPARATOR); define("CONFIG_PATH", ROOT_PATH ."config" . DIRECTORY_SEPARATOR); define("LIBRARY_PATH", ROOT_PATH ."library" . DIRECTORY_SEPARATOR); define("ST_PATH", ROOT_PATH ."st" . DIRECTORY_SEPARATOR); include CONFIG_PATH . "config.php"; include LIBRARY_PATH . "core.php"; Core::run($config); // main函数,入口函数
在index.php中除了定义一些全局宏变量,包含配置文件和核心类文件。只有一句运行代码,调用了核心类Core的run函数。
我们看看框架启动入口主函数Core::run($config)函数主要干啥子了?!
/** * 框架启动逻辑 * */ public static function run($config) { //获取配置文件 self::$_config = $config; //获取路由信息 $router = self::_parseUrl(); //自动加载核心类 self::autoLoad(); //调用控制器及其方法 self::initController($router); }
1. 获取配置文件
config配置主要配置:
- Controller的路由信息
- Model中需要的db和redis信息
- View中的模版引擎的相关信息
<?php /** * config.php * * 此配置文件在框架载入中就已经加载 * * @author linsunny<[email protected]> */ /** * 路由配置信息 * $config[router][‘show‘][1] = xx.com/index.php?c=controller&a=action * $config[router][‘show‘][2] = xx.com/index.php/controller/action */ $config[‘router‘] = array( ‘default_controller‘ => ‘index‘, ‘default_action‘ => ‘init‘, ‘show‘ => 2, ); /** * 模板引擎配置信息 * $config[‘smarty‘][‘suffix‘]表示模板文件的后缀名 * $config[‘smarty‘][‘isCache‘]表示是否用缓存 (默认不启动) * $config[‘smarty‘][‘cacheLeftTime‘]表示缓存有效期 (默认保存3600秒) */ $config[‘smarty‘] = array( ‘template_dir‘ => VIEW_PATH, ‘compile_dir‘ => CACHE_PATH . "compile" . DIRECTORY_SEPARATOR, ‘cache_dir‘ => CACHE_PATH . "cache" . DIRECTORY_SEPARATOR, ‘suffix‘ => ".htm", ‘isCache‘ => true, ‘cacheLeftTime‘ => 3600, ); /** *数据库配置 *$config[‘db‘][‘conn‘]表示数据库连接标识; pconn 为长久链接,默认为即时链接 */ $config[‘db‘] = array( ‘host‘ => ‘localhost‘, ‘user‘ => ‘root‘, ‘password‘ => ‘‘, ‘database‘ => ‘idou‘, ‘table_prefix‘ => ‘v1_‘, ‘charset‘ => ‘urf8‘, ‘conn‘ => ‘‘, ‘port‘ => 80 );
2. 解析Url获取路由信息
解析参数找到相应的Controller类以及该类的运行函数,以及函数参数
运行这个脚本 var/www/html/one-branch/index.php,然后解析后面?c=index&a=init带的参数,第一个参数以?分割,后续以&分割。
获取c的参数c=index,a=init.
3. 自动加载核心类
加载之前core文件夹中的核心类(model,view,controller,mysql),将这些代码路径require或者include进来。
4. 调用控制器及其方法
c标识controller, 故该类是indexController,c=index,a=init说明在Controller模块中找到indexController类,并且运行该类的indexController::init函数。
/** * 初始化控制器 * 调用对应控制器以及方法 * @class Core */ public static function initController($router) { static $codeAr = array();//定义静态变量储存数组,类似单例模式,这里用来存储控制方法逻辑 $key = $router[‘c‘] . "_" . $router[‘a‘]; $controller = $router[‘c‘] . "Controller"; $action = $router[‘a‘] . "Action"; //加载控制器文件 $controller_path = CONTROLLER_PATH . $controller . ".php"; self::loadFile($controller_path); //创建控制器 $object = new $controller(); if(method_exists($object, $action)){ $codeAr[$key] = $object->$action(); }else{ self::error("控制器方法不存在!"); } return $codeAr[$key]; }
接下来调用相应的indexController中的init函数。在init函数中先调用model函数读写db获得相应数据,再将相应数据assign给view,最后将view渲染display。
附上indexController的代码
/** * 页面显示 * 传入模板文件名,返回编译文件路径 * @access public * @return string */ public function display($file) { if(!$file) Core::error( ‘参数错误‘ ); $view_file = self::$config[‘template_dir‘] . $file; if( !file_exists($view_file) ) Core::error( $view_file . ‘模板文件不存在‘ ); $cache_file = self::$config[‘cache_dir‘] . md5($file); //当缓存文件存在且不过期时直接从缓存文件读取内容 if( $this->checkCacheExpire($cache_file, self::$config[‘cacheLeftTime‘]) ){ echo $this->readFile($cache_file); }else { extract($this->var);//注册key=value $view_content = $this->readFile($view_file);//读文件 $view_content = $this->replaceTag($view_content);//替换标签 $temp_file = self::$config[‘compile_dir‘] . md5($file).‘.htm.php‘; $this->writeFile($temp_file, $view_content); ob_start(); include($temp_file); $content = ob_get_contents(); ob_end_clean() ; if (self::$config[‘isCache‘]){ $this->writeFile($cache_file,$content) ;//编译好的内容写入缓存文件 } echo $content ; } }
之后附上本程序的流程图,以及本程序的日志文件。
后记
再此附上一张鸟哥的框架流程图。
也有人说框架应该叫做MVCD,D指的是Data,附上MVCD的一张图,说清楚1,2,3,4这几个步骤。
参考资料:
http://www.laruence.com/manual
https://github.com/linsunny/one
Question:
url链接除了可以带c和a参数以外,还可以带其他参数作为action函数的参数,所以parseUrl和initController的函数都还可以进行扩展。
可以扩展通过model读取到数据,然后赋值给view中的参数显示出来。