一、框架整體分析
在實現一個框架之前,我們需要了解這個框架應該達到一個怎樣的效果,按照傳統框架的思路,大致可以總結出以下這麼幾條:
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架构,对于这类网站的渗透更需要很好的理解。
一、框架整體分析
在實現一個框架之前,我們需要了解這個框架應該達到一個怎樣的效果,按照傳統框架的思路,大致可以總結出以下這麼幾條:
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架構,對於這類網站的滲透更需要很好的理解。
更多PHP微型框架設計 相關文章請關注PHP中文網!