Zend Framework框架路由機(jī)制代碼分析
本文分析了Zend Framework框架路由機(jī)制代碼。分享給大家供大家參考,具體如下:
在框架中,有關(guān)路由的調(diào)用關(guān)系為:
1、apache的mod_rewrite模塊把請求路由到框架的啟動腳本,一般是index.php;
2、前端控制器Zend_Controller_Front通過dispatch函數(shù)進(jìn)行請求分發(fā);
3、路由器Zend_Controller_Router_Rewrite通過route函數(shù)處理路由,對路由器中已有的路由規(guī)則,按照加入順序的逆序(類似于棧,后進(jìn)先出)對每個route調(diào)用match函數(shù),以檢查請求是否和當(dāng)前路由規(guī)則匹配,如果匹配的話把路由器的當(dāng)前路由這個變量($_currentRoute)設(shè)置為匹配的路由,并把route解析出來的參數(shù)傳給Zend_Controller_Request_Http對象,到這里完成路由設(shè)置。
如果沒有發(fā)現(xiàn)路由,框架會使用Index控制器的index這個action。
對Zend_Controller_Router_Route中的函數(shù)代碼分析:
1、構(gòu)造函數(shù)
public function __construct($route, $defaults = array(), $reqs = array())
{
$route = trim($route, $this->_urlDelimiter); //去掉規(guī)則首尾的url分隔符(默認(rèn)是/)
$this->_defaults = (array) $defaults; //默認(rèn)值數(shù)組,以變量名為鍵
$this->_requirements = (array) $reqs; //變量需要滿足的正則表達(dá)式,以變量名為鍵
if ($route != '') {
foreach (explode($this->_urlDelimiter, $route) as $pos => $part) {
//把規(guī)則切分為一個數(shù)組
if (substr($part, 0, 1) == $this->_urlVariable) {//如果是一個變量的定義
$name = substr($part, 1); //獲取變量名
//如果該變量定義了對應(yīng)的正則表達(dá)式,則獲取該表達(dá)式,否則置為null
$regex = (isset($reqs[$name]) ? $reqs[$name] : $this->_defaultRegex);
//_parts數(shù)組包含了規(guī)則的各個部分,如果是變量的話,數(shù)組中有name元素
$this->_parts[$pos] = array('name' => $name, 'regex' => $regex);
//_vars包含了該規(guī)則中的所有變量的名字
$this->_vars[] = $name;
} else { //普通字符串
$this->_parts[$pos] = array('regex' => $part);
if ($part != '*') {
$this->_staticCount++; //該規(guī)則的普通字符串的個數(shù)
}
}
}
}
}
2、匹配算法
public function match($path)
{
$pathStaticCount = 0;
$defaults = $this->_defaults; //默認(rèn)值數(shù)組,數(shù)組元素的鍵值是變量名
//默認(rèn)值數(shù)組的一個拷貝,不過變量的值全部換成布爾值,其實(shí)這個值并沒有實(shí)際用處,下面程序僅僅
//是通過判斷鍵值是否存在而確定是否包含一個變量,可能這么做是為了節(jié)省空間,不過要是這樣的話
//不如直接使用 $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是已經(jīng)去掉baseUrl的,這里確保去掉首尾的分隔符
if ($path != '') {
$path = explode($this->_urlDelimiter, $path);
foreach ($path as $pos => $pathPart) {
if (!isset($this->_parts[$pos])) {
//把path根據(jù)url分隔符分割為數(shù)組后,把每一部分和規(guī)則的對應(yīng)部分比較,如果path中存在,
//而規(guī)則中不存在對應(yīng)部分,那么該規(guī)則肯定不匹配,這里要注意$pos,是通過它把規(guī)則
//和path的對應(yīng)部分對應(yīng)起來。
return false;
}
if ($this->_parts[$pos]['regex'] == '*') {
//如果規(guī)則的當(dāng)前部分是通配符*,則把path的剩余部分解釋為url傳遞過來的變量,他們按照
//“變量名/變量值”這樣的形式成對出現(xiàn)
$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);//對傳過來的值進(jìn)行解碼
if ($name === null) {//普通字符串,和規(guī)則的對應(yīng)部分比較是否相等即可
if ($part['regex'] != $pathPart) {
return false;
}
} elseif ($part['regex'] === null) {
//如果是變量,但是沒有需要滿足的正則表達(dá)式,那么只有值不為空就可以了
if (strlen($pathPart) == 0) {
return false;
}
} else {//如果對該變量需要滿足一個正則表達(dá)式,那么這里進(jìn)行驗(yàn)證
$regex = $this->_regexDelimiter . '^' . $part['regex'] . '$' . $this->_regexDelimiter . 'iu';
if (!preg_match($regex, $pathPart)) {
return false;
}
}
if ($name !== null) {
// 如果是一個變量,則設(shè)置變量的值
$this->_values[$name] = $pathPart;
$unique[$name] = true; //其實(shí)沒有必要設(shè)置,這個版本根本就沒有用它
} else {
//把普通字符串的匹配計數(shù)加1,因?yàn)橐?guī)則中的普通字符串是必須在path中存在的,否則就是
//匹配失敗
$pathStaticCount++;
}
}
}
//$this->_values中保存的是分析獲取的變量,如果規(guī)則中存在‘*',則$this->_params是獲取的
//變量,否則是空數(shù)組,$this->_defaults是規(guī)則提供的默認(rèn)變量值,這里用‘+'把三個數(shù)組相加
//這樣的好處是如果后面的數(shù)組與前面的數(shù)組有相同的非整數(shù)的鍵值,后面的不會覆蓋前面的,這
//與array_merge函數(shù)有區(qū)別,后者是會覆蓋的。也就是說,如果$this->_values 中已經(jīng)有鍵controller
//,那么$this->_defaults中的controller元素就被忽略,這樣就$this->_defaults中的默認(rèn)值只有在path
//中不存在的時候才會出現(xiàn)在返回值中。
$return = $this->_values + $this->_params + $this->_defaults;
// Check if all static mappings have been met
if ($this->_staticCount != $pathStaticCount) {//規(guī)則的所有普通字符串必須在path中得到匹配
return false;
}
// 解析完后,規(guī)則定義的所有變量也必須全部出現(xiàn),否則視為不匹配
foreach ($this->_vars as $var) {
if (!array_key_exists($var, $return)) {
return false;
}
}
return $return;
}
更多關(guān)于zend相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Zend FrameWork框架入門教程》、《php優(yōu)秀開發(fā)框架總結(jié)》、《Yii框架入門及常用技巧總結(jié)》、《ThinkPHP入門教程》、《php面向?qū)ο蟪绦蛟O(shè)計入門教程》、《php+mysql數(shù)據(jù)庫操作入門教程》及《php常見數(shù)據(jù)庫操作技巧匯總》
希望本文所述對大家基于Zend Framework框架的PHP程序設(shè)計有所幫助。
- Zend Framework教程之路由功能Zend_Controller_Router詳解
- ThinkPHP、Zend?Framework2、Yaf、Laravel框架路由大比拼
- Zend Framework分發(fā)器用法示例
- Zend Framework動作控制器用法示例
- Zend Framework處理Json數(shù)據(jù)方法詳解
- Zend Framework入門教程之Zend_Registry組件用法詳解
- Zend Framework入門教程之Zend_Config組件用法詳解
- Zend Framework實(shí)現(xiàn)自定義過濾器的方法
- ZendFramework框架實(shí)現(xiàn)連接兩個或多個數(shù)據(jù)庫的方法
- Zend Framework框架實(shí)現(xiàn)類似Google搜索分頁效果
- Zend Framework開發(fā)入門經(jīng)典教程
- Zend Framework路由器用法實(shí)例詳解
相關(guān)文章
thinkPHP簡單調(diào)用函數(shù)與類庫的方法
這篇文章主要介紹了thinkPHP簡單調(diào)用函數(shù)與類庫的方法,簡單講述了thinkPHP公共函數(shù)庫的文件位置并結(jié)合實(shí)例分析了類庫的調(diào)用方法,需要的朋友可以參考下2017-03-03
ThinkPHP中SHOW_RUN_TIME不能正常顯示運(yùn)行時間的解決方法
這篇文章主要介紹了ThinkPHP中SHOW_RUN_TIME不能正常顯示運(yùn)行時間的解決方法,針對ThinkPHP配置文件config.php設(shè)置SHOW_RUN_TIME后不能顯示運(yùn)行時間情況下的解決方法,涉及針對ThinkPHP底層源文件的修改,需要的朋友可以參考下2015-10-10
在thinkphp5.0路徑中實(shí)現(xiàn)去除index.php的方式
今天小編就為大家分享一篇在thinkphp5.0路徑中實(shí)現(xiàn)去除index.php的方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-10-10
Laravel 5框架學(xué)習(xí)之表單驗(yàn)證
Laravel 通過 Validation 類讓您可以簡單、方便的驗(yàn)證數(shù)據(jù)正確性及查看相應(yīng)的驗(yàn)證錯誤信息。如果是更復(fù)雜的驗(yàn)證場景,你可能需要創(chuàng)建一個"表單請求"。表單請求是一個自定義的請求類包含了一些驗(yàn)證的邏輯。你可以通過 Artisan 的命令行 make:request 來創(chuàng)建一個表單請求類2015-04-04
Zend Framework教程之Zend_Db_Table_Row用法實(shí)例分析
這篇文章主要介紹了Zend Framework教程之Zend_Db_Table_Row用法,詳細(xì)講述了Zend_Db_Table_Row的功能,并結(jié)合實(shí)例形式詳細(xì)分析了Zend_Db_Table_Row操作數(shù)據(jù)的相關(guān)技巧,需要的朋友可以參考下2016-03-03

