一、框架整体分析
在实现一个框架之前,我们需要了解这个框架应该达到一个怎样的效果,按照传统框架的思路,大致可以总结出以下这么几条:
1.实现MVC架构,将控制、逻辑、视图层进行分离。
2.封装各种函数及功能模块,实现一处编写,多处调用,减少代码冗余。
3.便于扩展,可方便的引入外部扩展库,对自身框架进行增强。
4.选好设计模式,封装或编写各种引擎模块。
基本的框架需求大概就是这个样子,有了这些需求,接下来就是一个架构的设计,这里面涉及到的很多问题需要解决,下面我们一步步进行一个剖析。
二、框架设计过程
1.框架目录
这其实是个很重要的步骤,你的选择不同,最后目录结构也会有很大区别,除了满足基本的三层之外,扩展库,前端文件,模版,资源文件等也需要找目录放置,而这又决定了之后你的调用是否方便,我此次框架设计使用了smaty引擎作为视图引擎,目录结构大概如下:
这张图展示出了两级目录的一个结构,更深入的目录由于图片显示有限就不一一弄出来了,而每个目录及主要文件的作用会在后文一一说到。
2.目录介绍
(1)data目录
可以看到上图中的目录结构,由于使用了smarty引擎,而在smarty引擎中需要配置缓冲目录和缓存目录,因此data目录的作用就在于此。
(2)framework目录
该目录是我们框架的核心所在,db目录放置了我们的数据库操作函数库。function目录放置了一个function.php的文件,该文件的作用主要为方便以M(‘do’)这样的模式对各层方法的调用进行快速实例化。libs目录放置了框架的核心工厂类文件,如数据库的操作类,视图操作类,方便外部文件以如DB::funtion()这样的方式对这里面的方法进行调用。view放置了smarty视图引擎。include.list.php则是我们框架在调用时需要包含的文件,这里通通放在一个数组里进行保存。pc.php是我们的框架启动引擎,负责对我们的各个模块进行统一初始化,以及对我们的url进行解析处理。
(3)img目录
用于放置我们的样式文件、js文件以及其他相关的资源文件
(4)libs目录
该目录和framework下的libs目录名字虽然一样,但可以看到,该目录下放置的是MVC三层中的对应业务处理内容以及一个org扩展目录,Controller放置控制器、Model放置模型、View放置视图处理类。
(5)tpl目录
这个目录则放置一些模板文件,用于前端展示,可以看到我放置了admin和index两个目录,分别用于前台和后台的模板文件存放。
(6)admin.php和index.php
一般来说,采用mvc架构都会使用单入口模式,而这两个文件就是单入口模式的入口文件,用以启动该框架。
(7)config.php
这个基本所有的框架都有,配置文件,包含了比如数据库的配置,smarty引擎的配置,及一些静态变量的定义等。
这些所有的结构都只是该微型框架的一个基本结构,实际上复杂的框架会有很多扩展的函数以及外部插件,可以在这个目录结构上做出相应调整。
3.框架关键点
(1)控制器动态调用
单入口模式通常的url大概类似 index.php?controller=控制器&method=方法,在通过get方法获取到控制器和方法名之后,我们可以通过如下方式进行动态初始化
function C($name,$method){
require_once('/libs/Controller/'.$name.'Controller.class.php');
eval('$obj=new '.$name.'Controller();$obj->'.$method.'();');
}
function M($name){
require_once('/libs/Model/'.$name.'Model.class.php');
eval('$obj=new '.$name.'Model();');
return $obj;
}
function V($name){
require_once('/libs/View/'.$name.'View.class.php');
eval('$obj=new '.$name.'View();');
return $obj;
}
(2)原生方法改造
熟悉smarty的朋友都应该知道,smarty有assign和dispaly两个方法,分别用于注册变量和将变量输出到模版文件,但如果同时注册多个变量会让我们的代码变得很冗杂,所以我们尝试对这两个方法进行改造
public static function assign($data){
foreach ($data as $key => $value) {
self::$view->assign($key,$value);
}
}
public static function display($template){
self::$view->display($template);
}
我们让assign方法重写,让其可以直接注册数组,这样就减少了我们的后续代码量,如果要引入其它外部库,也可以通过这种方法对原生函数进行改造来使其更加适用。
(3)文件包含逻辑
本框架的启动文件为pc.php,因此,包含了pc.php就基本上包含了整个框架所需要用到的文件,先看一下一个入口文件index.php的内容。
header("Content-type:text/html;charset=utf-8");
date_default_timezone_set('Asia/Shanghai');
require_once('config.php');
require_once('framework/pc.php');
PC::run($config)
很简单,包含了配置文件和框架启动引擎pc.php,然后调用run方法启动该框架就可以,再看看pc.php的内容
$currentdir=dirname(__FILE__);
include_once($currentdir.'/include.list.php');
foreach ($paths as $path) {
include_once($currentdir.'/'.$path);
}
/**
* 完成一系列的初始化和调用控制器
*/
class PC
{
public static $controller;
public static $method;
private static $config;
private static function init_db(){
DB::init('mysql',self::$config['dbconfig']);
}
private static function init_view(){
VIEW::init('Smarty',self::$config['viewconfig']);
}
private static function init_controller(){
self::$controller=isset($_GET['controller'])?daddslashes($_GET['controller']):'index';
}
private static function init_method(){
self::$method=isset($_GET['method'])?daddslashes($_GET['method']):'index';
}
public static function run($config){
self::$config = $config;
self::init_db();
self::init_view();
self::init_controller();
self::init_method();
C(self::$controller,self::$method);
}
}
foreach遍历包含include.list.php中的所有文件,并将控制器和对应方法获取传递给C类进行自动包含。再看一下include.list.php有哪些东西
$paths=$arrayName = array(
'function/function.php',
'libs/core/DB.class.php',
'libs/core/VIEW.class.php',
'db/mysql.class.php',
'view/Smarty/Smarty.class.php'
);
这里面存储了一个数组,包含了咱们的两个工厂类、数据库操作类、外部引擎类、核心function类。
至此,可以梳理一下整个框架对一个url请求的处理流程:
(4)业务分离
mvc的核心就在于各层之间的严格分离,但Controller层和Model经常容易被混淆在一起,这样会导致mvc架构失去原有的意义,我们需要清楚,控制层只实现简单的控制和逻辑处理,不涉及到具体的业务和数据交互,所有的具体操作都应放到Model层。另外,这两层中的类名和文件名也应保持一致。
(5)方法控制
我们在通过url的形式调用控制器及方法时,某些方法是不想被外部调用到的,比如登录检查函数,这个时候我们可以通过将函数定义为私有函数的方式避免其直接被通过url的形式调用到,来防止风险的发生。
(6)扩展性设计
一个框架应该具备好的扩展性,尤其对于新外部库引入,应该能很容易通过简单修改就可以使用,因此应该将配置项单独分离存储。
三、总结
该框架基本设计就是这个样子,很简单,但基本实现了mvc架构,虽然和市面上的成熟框架相差很多,但重写一遍对于mvc的架构理解会更加深入,加之如今越来越多的网站都采用的这种单入口mvc架构,对于这类网站的渗透更需要很好的理解。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。