一、架構整體分析
在實現一個架構之前,我們需要瞭解這個架構應該達到一個怎樣的效果,按照傳統架構的思路,大致可以總結出以下這麼幾條:
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架構,對於這類網站的滲透更需要很好的理解。