本文分析了Zend Framework框架路由機制代碼。分享給大家供大家參考,具體如下:
在框架中,有關路由的調用關系為:
1、apache的mod_rewrite模塊把請求路由到框架的啟動腳本,一般是index.php;
2、前端控制器Zend_Controller_Front通過dispatch函數進行請求分發;
3、路由器Zend_Controller_Router_Rewrite通過route函數處理路由,對路由器中已有的路由規則,按照加入順序的逆序(類似於棧,後進先出)對每個route調用match函數,以檢查請求是否和當前路由規則匹配,如果匹配的話把路由器的當前路由這個變量($_currentRoute)設置為匹配的路由,並把route解析出來的參數傳給Zend_Controller_Request_Http對象,到這裡完成路由設置。
如果沒有發現路由,框架會使用Index控制器的index這個action。
對Zend_Controller_Router_Route中的函數代碼分析:
1、構造函數
public function __construct($route, $defaults = array(), $reqs = array()) { $route = trim($route, $this->_urlDelimiter); //去掉規則首尾的url分隔符(默認是/) $this->_defaults = (array) $defaults; //默認值數組,以變量名為鍵 $this->_requirements = (array) $reqs; //變量需要滿足的正則表達式,以變量名為鍵 if ($route != '') { foreach (explode($this->_urlDelimiter, $route) as $pos => $part) { //把規則切分為一個數組 if (substr($part, 0, 1) == $this->_urlVariable) {//如果是一個變量的定義 $name = substr($part, 1); //獲取變量名 //如果該變量定義了對應的正則表達式,則獲取該表達式,否則置為null $regex = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex); //_parts數組包含了規則的各個部分,如果是變量的話,數組中有name元素 $this->_parts[$pos] = array('name' => $name, 'regex' => $regex); //_vars包含了該規則中的所有變量的名字 $this->_vars[] = $name; } else { //普通字符串 $this->_parts[$pos] = array('regex' => $part); if ($part != '*') { $this->_staticCount++; //該規則的普通字符串的個數 } } } } }
2、匹配算法
public function match($path) { $pathStaticCount = 0; $defaults = $this->_defaults; //默認值數組,數組元素的鍵值是變量名 //默認值數組的一個拷貝,不過變量的值全部換成布爾值,其實這個值並沒有實際用處,下面程序僅僅 //是通過判斷鍵值是否存在而確定是否包含一個變量,可能這麼做是為了節省空間,不過要是這樣的話 //不如直接使用 $this->_defaults了? if (count($defaults)) { $unique = array_combine(array_keys($defaults), array_fill(0, count($defaults), true)); } else { $unique = array(); } $path = trim($path, $this->_urlDelimiter); //傳入的path是已經去掉baseUrl的,這裡確保去掉首尾的分隔符 if ($path != '') { $path = explode($this->_urlDelimiter, $path); foreach ($path as $pos => $pathPart) { if (!isset($this->_parts[$pos])) { //把path根據url分隔符分割為數組後,把每一部分和規則的對應部分比較,如果path中存在, //而規則中不存在對應部分,那麼該規則肯定不匹配,這裡要注意$pos,是通過它把規則 //和path的對應部分對應起來。 return false; } if ($this->_parts[$pos]['regex'] == '*') { //如果規則的當前部分是通配符*,則把path的剩余部分解釋為url傳遞過來的變量,他們按照 //“變量名/變量值”這樣的形式成對出現 $parts = array_slice($path, $pos); //獲取path的剩余部分 $this->_getWildcardData($parts, $unique); break; } $part = $this->_parts[$pos]; $name = isset($part['name']) ? $part['name'] : null; $pathPart = urldecode($pathPart);//對傳過來的值進行解碼 if ($name === null) {//普通字符串,和規則的對應部分比較是否相等即可 if ($part['regex'] != $pathPart) { return false; } } elseif ($part['regex'] === null) { //如果是變量,但是沒有需要滿足的正則表達式,那麼只有值不為空就可以了 if (strlen($pathPart) == 0) { return false; } } else {//如果對該變量需要滿足一個正則表達式,那麼這裡進行驗證 $regex = $this->_regexDelimiter . '^' . $part['regex'] . '$' . $this->_regexDelimiter . 'iu'; if (!preg_match($regex, $pathPart)) { return false; } } if ($name !== null) { // 如果是一個變量,則設置變量的值 $this->_values[$name] = $pathPart; $unique[$name] = true; //其實沒有必要設置,這個版本根本就沒有用它 } else { //把普通字符串的匹配計數加1,因為規則中的普通字符串是必須在path中存在的,否則就是 //匹配失敗 $pathStaticCount++; } } } //$this->_values中保存的是分析獲取的變量,如果規則中存在‘*',則$this->_params是獲取的 //變量,否則是空數組,$this->_defaults是規則提供的默認變量值,這裡用‘+'把三個數組相加 //這樣的好處是如果後面的數組與前面的數組有相同的非整數的鍵值,後面的不會覆蓋前面的,這 //與array_merge函數有區別,後者是會覆蓋的。也就是說,如果$this->_values 中已經有鍵controller //,那麼$this->_defaults中的controller元素就被忽略,這樣就$this->_defaults中的默認值只有在path //中不存在的時候才會出現在返回值中。 $return = $this->_values + $this->_params + $this->_defaults; // Check if all static mappings have been met if ($this->_staticCount != $pathStaticCount) {//規則的所有普通字符串必須在path中得到匹配 return false; } // 解析完後,規則定義的所有變量也必須全部出現,否則視為不匹配 foreach ($this->_vars as $var) { if (!array_key_exists($var, $return)) { return false; } } return $return; }
更多關於zend相關內容感興趣的讀者可查看本站專題:《Zend FrameWork框架入門教程》、《php優秀開發框架總結》、《Yii框架入門及常用技巧總結》、《ThinkPHP入門教程》、《php面向對象程序設計入門教程》、《php+mysql數據庫操作入門教程》及《php常見數據庫操作技巧匯總》
希望本文所述對大家基於Zend Framework框架的PHP程序設計有所幫助。