先說一下這個項目的代碼結構吧。
首先是index.php,我是把它作為中央控制器,一個調度器。程序通過rewrite或其他方式,把所有url導向本文件,由index.php調度其他代碼。
然后route.php,用設置好的路由規則匹配當前的url,來選擇響應的controller(下面解釋)來處理request,返回response。
request.php,本文件用來解析requset信息(頭部信息:method,accept,querystring,請求body的數據(主要為json格式)等),保存到內存里等待其他程序使用。
response.php,本文件用來生成response信息(body數據(json格式),設置狀態碼,content-type等),返回給客戶端。
controller文件夾內的文件,這些文件用來處理具體業務邏輯,根據request.php,操作數據庫,使用response.php生成結果返回給客戶端。
db.php由名字可知,本文件為數據庫操作類(mysql)。
還有其他類如日志功能,身份驗證等等以后再實現吧。
Rewite
應用程序首先將所有url導向到index.php。可以使用Apache服務器mod_rewrite重寫轉向(Rewrite)模塊來實現。由於我的web服務搭建在新浪SAE,它本身的config.yaml具有url重寫功能,只需要加入一句 - rewrite: if(!is_file()) goto "index.php?%{QUERY_STRING}" 就可以了(config.yaml配置可參閱SAE相關文檔)。
Route
首先在router.php配置相關規則:
<?php /** *路由配置文件編寫說明: * 路由配置在一個array數組中,一條記錄代表一個規則 * 優先匹配索引低的規則 * key: 只接受2中規則 '/{controller}'和'/{controller}/{id}'。{controller}可用字符包括:字母,數字,_ * value: 第一項controller類名(文件名除去擴展名必須與類名相同); * 第二項id只能為正整數(包含0) * controller文件必須位於'/controller'文件夾下;類名必須與文件名相同(除去擴展名.php),區分大小寫。 **/ $routes= array( '/resources' => array('resources',''), '/resources/id' => array('resources','id'), ); ?>
routes數組保存應用程序的相關規則,由於時間緊迫,設置規則十分不靈活,后期需要加以修改,規則及其解析我們都可以隨時進行調整。routes數組key為需要匹配的url,value為響應的controller名字。前文我們有提到,我們只需要處理2種url :'/resources' => array('resources','')表示匹配到/resources時,選擇controller文件下的resources.php文件內的resources類來處理。'/resources/id' => array('resources','id'),大同小異,只不過我們需要,匹配並保存url中第二層的id。
然后route.php解析上面的規則:
<?php class Route { private $filepath; private $classname; private $id; private $routepatterns; public function __construct() { $this->filepath = ''; $this->classname = ''; $this->id = null; $this->routepatterns = array(); $this->initRoutes(); } private function initRoutes() { $reg_m1 = '#^/(\w+)$#'; $reg_m2 = '#^/(\w+)/id$#'; $matches = array(); $routes = array(); include 'router.php'; foreach($routes as $key=>$value){ if(preg_match($reg_m1,$key,$matches)){ $this->routepatterns[] = array('#^/('.$matches[1].')\??$#i', array('controller/'.$value[0].'.php',$value[0])); } else if(preg_match($reg_m2,$key,$matches)){ $this->routepatterns[] = array('#^/('.$matches[1].')/(\d+)\??$#i', array('controller/'.$value[0].'.php',$value[0])); } } } public function processURL($urlpath) { $matches = array(); foreach($this->routepatterns as $router){ if(preg_match($router[0],$urlpath,$matches)){ $filepath_ = '/'.$router[1][0]; $classname_ = $router[1][1]; $id_ = count($matches)>2?$matches[2]:null; $this->setFilePath($filepath_); $this->setClassName($classname_); $this->setID($id_); return true; } } return false; } public function setFilePath($filepath) { $this->filepath = $filepath; } public function setClassName($classname) { $this->classname = $classname; } public function setID($id) { $this->id = $id; } public function getFilePath() { return $this->filepath; } public function getClassName() { return $this->classname; } public function getID() { return $this->id; } } ?>
私有方法initRoutes(),是一個預處理方法。它解析了routes所有規則,保存routepatterns中,等待使用。processURL($urlpath)方法使用解析出的routepatterns匹配傳入url,獲取相應的結果,並記錄下來。
processURL($urlpath)方法是Rote類的核心,它將傳入的url用之前定義的路由規則匹配。成功則獲取controller,id(如果有),返回true;失敗返回false。