PHP雖然是一門新語言,但是如果程式語言寫的好容易上手。以下是本站小編精心為大家整理的PHP教程,希望對大家有所幫助!更多內容請關注應屆畢業生網!
曾幾何時,我們公司準備開發一套新的建站系統,決定將以前的框架給KO掉,重新開發一套新的框架來適應新的系統功能。領導們不希望使用外面已有的框架,號稱要開發有自己特色的框架(不懂開發的領導害死人)。於是我們又投入到了新的開發當中。
由於我們的系統支援偽靜態,以前的系統是直接使用伺服器apache或IIS自帶的rewrite檔案定義規則,而框架中沒有任何路由機制,於是這次框架準備使用新的策略,由PHP實現路由機制。於是我開始了功能實現的探索之路。
開發之前,我先了解‘路由機制’要做什麼,它主要做兩件事。
1.路由機制就是把某一個特定形式的URL結構中提煉出來系統對應的引數。舉個例子,如: 其中:/article/1 -> ?_m=article&id=1。
2.其次,是將擁有對應引數的URL轉換成特定形式的URL結構,是上面的過程的逆向過程。由於路由機制隔離了URL結構和引數的轉換關係,使的.日後結構的變化不會影響下面程式碼的執行。
通過上面的瞭解,可以得出要編寫一個路由機制要一下幾步:
1.編寫伺服器apache或IIS自帶的rewrite檔案,將URL結構匯入。
2.一個路由規則配置檔案。
3.一個路由解析器,用來解析規則,匹配和轉換URL。
於是,我們一一實現其中的每一個部分。
ite檔案編寫,以Apache為例:
1234567 | <IfModulemod_rewrite.c> RewriteEngineOn RewriteRule^index$-[L] RewriteCond%{REQUEST_FILENAME}!-f RewriteCond%{REQUEST_FILENAME}!-d RewriteRule(.+) $1 [L] </IfModule> |
上面的程式碼就是將URL結構匯入中,具體的rewrite細節就不贅述了。
2.在PHP中設定一個路由規則配置檔案,我簡單的使用了一個hash陣列編寫規則:
123456789101112131415161718192021222324 | /**
*路由配置檔案編寫說明:
*路由配置在一個array陣列中,一條記錄代表一個規則
*其中陣列key的資料代表匹配的路徑格式:使用特定的字串標識如:'/{id}'
*字串中可以包含特定的變數,所有變數使用大括號{}包裹起來
*陣列value裡是一個array陣列,是對key中路徑中變數進行特定處理
*變數寫在陣列的key中,規範寫在陣列的value裡,如:array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')
*規範分成兩類:
*1.格式判斷:比如'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')為例,其中'id'=>'/d+/'就是一個格式判斷,
*表示id變數只能是數字,格式判斷後面只能使用正則表示式,由於PHP沒有正則類,所以我指定'/XXX/'和'#XXX#'格式的字串為正則表示式
*2.預設引數:比如'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')為例,其中'_m'=>'frontpage'就是一個預設引數,
*因為前面的路徑沒有_m和_a資訊,所以後面會使用預設引數作為_m和_a的值
*
*所以對於規則'/{id}'=>array('id'=>'/d+/','_m'=>'frontpage','_a'=>'index')。我傳入/3系統會轉換成_a=index&id=3
*
*規則匹配是按照$routes陣列的順序逐一匹配,一旦匹配上了就不往下匹配了。所以一些特定的匹配規則要放在前面,通用的放在後面。
*否則可能導致不執行特定的匹配規則了
*/ $routes = array ( '/' => array ( '_m' => 'wp_frontpage' , '_a' => 'index' ), '/{id}' => array ( 'id' => '/d+/' , '_m' => 'wp_frontpage' , '_a' => 'index' ), '/{_m}/{_a}/{id}' => array ( 'id' => '/d+/' ), '/{_m}/{_a}' => array () ); |
3.路由機制中最複雜也是最重要的一部分,就是解析器。
解析器有兩個類組成(名字可能起的不佳)。
一個是Route,作為整個解析器對外的介面,用於解析規則,匹配和轉換URL,然而它只是一個代理,實際操作不是直接由它直接做的。
一個是RoutePattern,每個RoutePattern例項對應規則陣列中的一條記錄,一個Route例項包含多個RoutePattern,而Route中的所有操作都會呼叫內部所有RoutePattern例項操作,並進行整合。
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 | class Route { private static $instance =null; private $routepatterns = array (); private function __construct() { $routes = array (); include ROOT. "/" ; foreach ( $routes as $key => $value ){ $this ->routepatterns[]= new RoutePattern( $key , $value ); }
if (!isset( $_SERVER [ 'PATH_INFO' ])) return false; $urlpath = $_SERVER [ 'PATH_INFO' ]; $ismatch = $this ->match_url( $urlpath ); $strip_urlpath = str_replace ( '/' , '' , $urlpath ); if (! $ismatch &&! empty ( $strip_urlpath )){ Content::redirect(PAGE_404); } } /** *用路由規則匹配對應的url地址,匹配成功將對應url引數放入$_GET中 *@paramstringurl地址 *@returnbool是否匹配成功 */ public function match_url( $urlpath ){ foreach ( $this ->routepatterns as $router ){ $urlargs = $router ->match_url( $urlpath ); if ( $urlargs !==false){ $_GET = array_merge ( $urlargs , $_GET ); return true; } } return false; } public function rewrite_url( $urlparams ){ foreach ( $this ->routepatterns as $router ){ $urlstr = $router ->rewrite_url( $urlparams ); if ( $urlstr !==false){ return $urlstr ; } } $actualparams = array (); foreach ( $urlparams as $arg => $val ){ $actualparams []= $arg . "=" ncode( $val ); } $actualparamstr =implode( '&' , $actualparams ); $rewriteurl = "/" ; if (! empty ( $rewriteurl )) $rewriteurl .= "?{$actualparamstr}" ; return $rewriteurl ; } public static function init() { if (null==self:: $instance ){ self:: $instance = new Route(); } return self:: $instance ;
} } class RoutePattern{ //...... } |