在Web開發中,對于URL有一些共性的需求,如:
* 統一、簡潔的URL創建方式
* URL的偽靜態化(美化)處理
* 從URL中解析出相應的路由信息,引導應用執行后續處理
這些功能在 前面我們講的 UrlRule 層面已經得到了一定程度的實現。 但從層次上來講,UrlRule 更偏向于基礎一些,直接使用 UrlRule 相對而言還不是很方便。
比如,針對各種類型的URL,我們需要提供相應的 UrlRule 實例來進行處理。 這些實例如何進行統一管理,相互關系怎么處理?都無法在 UrlRule 自身層面解決。
我們需要更貼近開發的接口。于是Yii把Web應用中對于URL的常用要求抽象到了urlManager中, 并作為Web應用的核心組件,更便于開發者使用。
## urlManager概覽[](http://www.digpage.com/urlmanager.html#id1 "Permalink to this headline")
urlManager組件由?yii\web\UrlManager?類定義:
~~~
class UrlManager extends Component
{
// 用于表明urlManager是否啟用URL美化功能,在Yii1.1中稱為path格式URL,
// Yii2.0中改稱美化。
// 默認不啟用。但實際使用中,特別是產品環境,一般都會啟用。
public $enablePrettyUrl = false;
// 是否啟用嚴格解析,如啟用嚴格解析,要求當前請求應至少匹配1個路由規則,
// 否則認為是無效路由。
// 這個選項僅在 enablePrettyUrl 啟用后才有效。
public $enableStrictParsing = false;
// 保存所有路由規則的配置數組,并不在這里保存路由規則的實例
public $rules = [];
// 指定續接在URL后面的一個后綴,如 .html 之類的。僅在 enablePrettyUrl 啟用時有效。
public $suffix;
// 指定是否在URL在保留入口腳本 index.php
public $showScriptName = true;
// 指定不啟用 enablePrettyUrl 情況下,URL中用于表示路由的查詢參數,默認為 r
public $routeParam = 'r';
// 指定應用的緩存組件ID,編譯過的路由規則將通過這個緩存組件進行緩存。
// 由于應用的緩存組件默認為 cache ,所以這里也默認為 cache 。
// 如果不想使用緩存,需顯式地置為 false
public $cache = 'cache';
// 路由規則的默認配置,注意上面的 rules[] 中的同名規則,優先于這個默認配置的規則。
public $ruleConfig = ['class' => 'yii\web\UrlRule'];
private $_baseUrl;
private $_scriptUrl;
private $_hostInfo;
// urlManager 初始化
public function init()
{
parent::init();
// 如果未啟用 enablePrettyUrl 或者沒有指定任何的路由規則,
// 這個urlManager不需要進一步初始化。
if (!$this->enablePrettyUrl || empty($this->rules)) {
return;
}
// 初始化前, $this->cache 是緩存組件的ID,是個字符串,需要獲取其實例。
if (is_string($this->cache)) {
// 如果獲取不到實例,說明應用不提供緩存功能,
// 那么置這個 $this->cache 為false
$this->cache = Yii::$app->get($this->cache, false);
}
// 如果順利引用到了緩存組件,那么就將路由規則緩存起來
if ($this->cache instanceof Cache) {
// 以當前urlManager類的類名為緩存的鍵
$cacheKey = __CLASS__;
// urlManager所有路由規則轉換為json格式編碼后的HASH值,
// 用于確保緩存中的路由規則沒有變化。
// 即外部沒有對已經緩存起來的路由規則有增加、修改、
// 刪除、調整前后位置等操作。
$hash = md5(json_encode($this->rules));
// cache中是一個數組, 0號元素用于緩存創建好的路由規則,
// 1號元素用于保存HASH值。這個判斷用于確認是否有緩存、且緩存仍有效。
// 是的話,直接使用緩存中的內容作為當前的路由規則數組。
if (($data = $this->cache->get($cacheKey)) !== false
&& isset($data[1]) && $data[1] === $hash) {
$this->rules = $data[0];
// 如果尚未緩存或路由規則已經被修改導致緩存失效,
// 那么重新創建路由規則并緩存。
} else {
$this->rules = $this->buildRules($this->rules);
$this->cache->set($cacheKey, [$this->rules, $hash]);
}
// 要么是應用不提供緩存功能,要么是開發者將 $this->cache 手動置為false,
// 總之,就是不使用緩存。那么就直接創建吧,也無需緩存了。
} else {
$this->rules = $this->buildRules($this->rules);
}
}
// 增加新的規則
public function addRules($rules, $append = true){ ... }
// 創建路由規則
protected function buildRules($rules){ ... }
// 用于解析請求
public function parseRequest($request){ ... }
// 這2個用于創建URL
public function createUrl($params){ ... }
public function createAbsoluteUrl($params, $scheme = null){ ... }
}
~~~
在urlManager的使用上,用得最多的配置項就是:
* $enablePrettyUrl?,是否開啟URL美化功能。關于美化功能,我們在?[_路由(Route)_](http://www.digpage.com/route.html#route)?部分已經介紹過了。 注意如果?$enablePrettyUrl?不開啟,表明使用原始的格式,那么所有路由規則都是無效的。
* $showScriptName?,是否在URL中顯示入口腳本。是對美化功能的進一步補充。
* suffix?設置一個?.html?之類的假后綴,是對美化功能的進一步補充。
* rules?保存路由規則們的聲明,注意并非保存其實例。
* $enableStrictParsing?是否開啟嚴格解析。該選項僅在開啟美化功能后生效。在開啟嚴格解析模式時, 所有請求必須匹配?$rules[]?所聲明的至少一個路由規則。 如果未開啟,請求的PATH_INFO部分將作為所請求的路由進行后續處理。
在?UrlManager::init()?初始化過程中,可以發現 urlManager 使用了應用所提供的緩存組件(有果有的話), 對所有路由規則的實例進行緩存。
從架構上來講,將所有請求交由入口腳本統一接收,再分發到相應模塊進行處理的這種方式, 就注定了入口腳本有產生性能瓶頸的可能。但是帶來的開發上的便利,卻是實實在在的。 可以想像,在由Web Server進行請求分發的情景下,每個接收請求的腳本都要執行相同或類似的代碼, 這會造成很冗余。而且會將權限控制、日志記錄等邏輯上就應當作為所有請求第一關的的模塊都分散到各處去。
因此,目前這種單一入口腳本的設計成為事實上的標準,幾乎所有的Web開發框架都采用這種方式。 但這同時也對各框架的性能提出挑戰。
在前面講路由規則時,我們就體會到了初始化過程的繁瑣,轉換來轉換去的。 如果采用簡單粗暴的方式,Yii完全可以犧牲一定的開發便利性,在代碼層面提高路由規則的性能。 比如,直接使用正則表達式。
但是,Yii沒有這樣做,而是很好地平穩了性能與開發便利性,通過將路由規則進行緩存來克服這個瓶頸。
TBD
如果覺得《深入理解Yii2.0》對您有所幫助,也請[幫助《深入理解Yii2.0》](http://www.digpage.com/donate.html#donate)。 謝謝!
- 更新記錄
- 導讀
- Yii是什么
- Yii2.0的亮點
- 背景知識
- 如何閱讀本書
- Yii基礎
- 屬性(Property)
- 事件(Event)
- 行為(Behavior)
- Yii約定
- Yii應用的目錄結構和入口腳本
- 別名(Alias)
- Yii的類自動加載機制
- 環境和配置文件
- 配置項(Configuration)
- Yii模式
- MVC
- 依賴注入和依賴注入容器
- 服務定位器(Service Locator)
- 請求與響應(TBD)
- 路由(Route)
- Url管理
- 請求(Reqeust)
- Web應用Request
- Yii與數據庫(TBD)
- 數據類型
- 事務(Transaction)
- AcitveReocrd事件和關聯操作
- 樂觀鎖與悲觀鎖
- 《深入理解Yii2.0》視頻教程
- 第一講:基礎配置
- 第二講:用戶登錄
- 第三講:文章及評論的模型
- 附錄
- 附錄1:Yii2.0 對比 Yii1.1 的重大改進
- 附錄2:Yii的安裝
- 熱心讀者