php 創建簡單的Restful WebAPI(二)


  先說一下這個項目的代碼結構吧。

  首先是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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM