# 快速入門(二):URL和路由
本章講解`URL`訪問和路由的使用,主要包含:
- - [URL訪問](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#url-)
- [參數傳入](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u53C2u6570u4F20u5165)
- [隱藏index.php](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#-index-php)
- [定義路由](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u5B9Au4E49u8DEFu7531)
- [完整匹配](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u5B8Cu6574u5339u914D)
- [閉包定義](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u95EDu5305u5B9Au4E49)
- [設置URL分隔符](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#-url--1)
- [路由參數](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u8DEFu7531u53C2u6570)
- [變量規則](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u53D8u91CFu89C4u5219)
- [路由分組](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u8DEFu7531u5206u7EC4)
- [復雜路由](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u590Du6742u8DEFu7531)
- [生成URL地址](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#-url--2)
- [總結](http://www.hmoore.net/thinkphp/thinkphp5_quickstart/145250#u603Bu7ED3)
## URL訪問
`ThinkPHP`采用單一入口模式訪問應用,對應用的所有請求都定向到應用的入口文件,系統會從`URL`參數中解析當前請求的模塊、控制器和操作,下面是一個標準的`URL`訪問格式:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//serverName/index.php/模塊/控制器/操作</span>
```
```
> #### 提示:
>
> - - - - - -
>
> 模塊在ThinkPHP中的概念其實就是應用目錄下面的子目錄,而官方的規范是目錄名小寫,因此模塊全部采用小寫命名,無論URL是否開啟大小寫轉換,模塊名都會強制小寫。
應用的`index`模塊的`Index`控制器定義如下:
```
<pre class="calibre18">
```
<span class="hljs-operator"><span class="hljs-number"><?php</span><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>;
<span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span></span>{
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-number">()</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'index'</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span><span class="hljs-number">(<span class="hljs-regexp">$name</span> = <span class="hljs-string">'World'</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'!'</span>;
}
}</span>
```
```
如果我們直接訪問入口文件的話,由于URL中沒有模塊、控制器和操作,因此系統會訪問默認模塊(index)下面的默認控制器(Index)的默認操作(index),因此下面的訪問是等效的:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>
```
```
如果要訪問控制器的hello方法,則需要使用完整的URL地址
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/name/thinkphp
```
```
訪問URL地址后頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,thinkphp!
```
```
由于`name`參數為可選參數,因此也可以使用
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello
```
```
訪問URL地址后頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,World!
```
```
默認情況下,URL地址中的控制器和操作名是不區分大小寫的,因此下面的訪問其實是等效的:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/Index/Index
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/INDEX/INDEX
```
```
如果你的控制器是駝峰的,例如定義一個HelloWorld控制器(`application/index/controller/HelloWorld.php`):
```
<pre class="calibre18">
```
<span class="hljs-operator"><span class="hljs-number"><?php</span><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>;
<span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWorld</span></span>{
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-number">(<span class="hljs-regexp">$name</span> = <span class="hljs-string">'World'</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'!'</span>;
}
}</span>
```
```
正確的URL訪問地址(該地址可以使用url方法生成)應該是:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/hello_world/<span class="hljs-keyword">index</span>
```
```
系統會自動定位到`HelloWorld`控制器類去操作。
如果使用
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/HelloWorld/<span class="hljs-keyword">index</span>
```
```
將會報錯,并提示`Helloworld`控制器類不存在。
如果希望嚴格區分大小寫訪問(或者要支持駝峰法進行控制器訪問),可以在應用配置文件中設置:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 關閉URL自動轉換(支持駝峰訪問控制器)</span><span class="hljs-string">'url_convert'</span> => <span class="hljs-keyword">false</span>,
```
```
關閉URL自動轉換之后,必須使用下面的URL地址訪問(控制器名稱必須嚴格使用控制器類的名稱,不包含控制器后綴):
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/Index/<span class="hljs-keyword">index</span>
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/HelloWorld/<span class="hljs-keyword">index</span>
```
```
> #### 提示:
>
> - - - - - -
>
> 操作方法的訪問本身不會受URL自動轉換的影響,但會影響默認的模板渲染輸出。
如果你的服務器環境不支持`pathinfo`方式的URL訪問,可以使用兼容方式,例如:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php?<span class="hljs-keyword">s</span>=<span class="hljs-regexp">/index/</span>Index/<span class="hljs-keyword">index</span>
```
```
其中變量`s`的名稱的可以配置的。
> 5.0不再支持普通的URL訪問方式,所以下面的訪問是無效的,你會發現無論輸入什么,訪問的都是默認的控制器和操作^\_^
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/index.php?m=index&c=Index&a=hello</span>
```
```
## 參數傳入
通過操作方法的參數綁定功能,可以實現自動獲取URL的參數,仍然以上面的控制器為例,控制器代碼如下:
```
<pre class="calibre18">
```
<span class="hljs-operator"><span class="hljs-number"><?php</span><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>;
<span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">Index</span></span>{
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">index</span><span class="hljs-number">()</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'index'</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span><span class="hljs-number">(<span class="hljs-regexp">$name</span> = <span class="hljs-string">'World'</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'!'</span>;
}
}</span>
```
```
當我們訪問
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello
```
```
就是訪問`app\index\controller\Index`控制器類的`hello`方法,因為沒有傳入任何參數,`name`參數就使用默認值`World`。如果傳入name參數,則使用:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/name/thinkphp
```
```
頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,thinkphp!
```
```
現在給hello方法增加第二個參數:
```
<pre class="calibre18">
```
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hello</span><span class="hljs-number">(<span class="hljs-regexp">$name</span> = <span class="hljs-string">'World'</span>, <span class="hljs-regexp">$city</span> = <span class="hljs-string">''</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'! You come from '</span> . <span class="hljs-regexp">$city</span> . <span class="hljs-string">'.'</span>;
}
```
```
訪問地址為
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/name/thinkphp/city/shanghai
```
```
頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,thinkphp! You come <span class="hljs-keyword">from</span> shanghai.
```
```
可以看到,`hello`方法會自動獲取URL地址中的同名參數值作為方法的參數值,而且這個參數的傳入順序不受URL參數順序的影響,例如下面的URL地址輸出的結果和上面是一樣的:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/city/shanghai/name/thinkphp
```
```
或者使用
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello?city=shanghai&name=thinkphp
```
```
還可以進一步對URL地址做簡化,前提就是我們必須明確參數的順序代表的變量,我們更改下URL參數的獲取方式,把應用配置文件中的`url_param_type`參數的值修改如下:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 按照參數順序獲取</span><span class="hljs-string">'url_param_type'</span> => <span class="hljs-number">1</span>,
```
```
現在,URL的參數傳值方式就變成了嚴格按照操作方法的變量定義順序來傳值了,也就是說我們必須使用下面的URL地址訪問才能正確傳入`name`和`city`參數到`hello`方法:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/thinkphp/shanghai
```
```
頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,thinkphp! You come <span class="hljs-keyword">from</span> shanghai.
```
```
如果改變參數順序為
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/shanghai/thinkphp
```
```
頁面輸出結果為:
```
<pre class="calibre18">
```
Hello,shanghai! You come <span class="hljs-keyword">from</span> thinkphp.
```
```
顯然不是我們預期的結果。
同樣,我們試圖通過
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello/name/thinkphp/city/shanghai
```
```
訪問也不會得到正確的結果。
但下面的方式仍然可以得到正確的結果:
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>.php/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello?name=thinkphp&city=shanghai
```
```
> #### 注意
>
> - - - - - -
>
> 按順序綁定參數的話,操作方法的參數只能使用URL pathinfo變量,而不能使用get或者post變量。
## 隱藏index.php
可以去掉URL地址里面的入口文件`index.php`,但是需要額外配置WEB服務器的重寫規則。
以`Apache`為例,需要在入口文件的同級添加`.htaccess`文件(官方默認自帶了該文件),內容如下:
```
<pre class="calibre18">
```
<span class="hljs-regexp"><IfModule mod_rewrite.c></span><span class="hljs-keyword"><span class="hljs-operator">Options</span></span> +FollowSymlinks -Multiviews
<span class="hljs-keyword"><span class="hljs-operator">RewriteEngine</span></span> <span class="hljs-number">on</span><span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-d
<span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-f
<span class="hljs-keyword"><span class="hljs-operator">RewriteRule</span></span> ^(.*)$ index.php/<span class="hljs-number">$1</span><span class="hljs-operator"> [QSA,PT,L]</span><span class="hljs-regexp"></IfModule></span>
```
```
如果用的`phpstudy`,規則如下:
```
<pre class="calibre18">
```
<span class="hljs-regexp"><IfModule mod_rewrite.c></span><span class="hljs-keyword"><span class="hljs-operator">Options</span></span> +FollowSymlinks -Multiviews
<span class="hljs-keyword"><span class="hljs-operator">RewriteEngine</span></span> <span class="hljs-number">on</span><span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-d
<span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-f
<span class="hljs-keyword"><span class="hljs-operator">RewriteRule</span></span> ^(.*)$ index.php<span class="hljs-operator"> [L,E=PATH_INFO:$1]
</IfModule></span>
```
```
接下來就可以使用下面的URL地址訪問了
```
<pre class="calibre18">
```
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>
http:<span class="hljs-regexp">//tp</span>5.com/<span class="hljs-keyword">index</span>/<span class="hljs-keyword">index</span>/hello
```
```
如果你使用的`apache`版本使用上面的方式無法正常隱藏`index.php`,可以嘗試使用下面的方式配置`.htaccess`文件:
```
<pre class="calibre18">
```
<span class="hljs-regexp"><IfModule mod_rewrite.c></span><span class="hljs-keyword"><span class="hljs-operator">Options</span></span> +FollowSymlinks -Multiviews
<span class="hljs-keyword"><span class="hljs-operator">RewriteEngine</span></span> <span class="hljs-number">on</span><span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-d
<span class="hljs-keyword"><span class="hljs-operator">RewriteCond</span></span> <span class="hljs-operator">%{REQUEST_FILENAME}</span> !-f
<span class="hljs-keyword"><span class="hljs-operator">RewriteRule</span></span> ^(.*)$ index.php?/<span class="hljs-number">$1</span><span class="hljs-operator"> [QSA,PT,L]</span><span class="hljs-regexp"></IfModule></span>
```
```
如果是`Nginx`環境的話,可以在`Nginx.conf`中添加:
```
<pre class="calibre18">
```
location / { // …..省略部分代碼
<span class="hljs-keyword">if</span> (!<span class="hljs-operator">-e</span> <span class="hljs-regexp">$request_filename</span>) {
rewrite ^(.*)$ /index.php?s=/<span class="hljs-regexp">$1</span> last;
<span class="hljs-number">break</span>;
}
}
```
```
> #### 提示:
>
> - - - - - -
>
> 后面的示例訪問地址,我們都假設配置了隱藏`index.php`。
## 定義路由
URL地址里面的`index`模塊怎么才能省略呢,默認的URL地址顯得有點長,下面就來說說如何通過路由簡化URL訪問。
我們在路由定義文件(`application/route.php`)里面添加一些路由規則,如下:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 添加路由規則 路由到 index控制器的hello操作方法</span><span class="hljs-string">'hello/:name'</span> => <span class="hljs-string">'index/index/hello'</span>,
];
```
```
該路由規則表示所有`hello`開頭的并且帶參數的訪問都會路由到`index`控制器的`hello`操作方法。
路由之前的URL訪問地址為:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>/<span class="hljs-regexp">/tp5.com/index</span><span class="hljs-regexp">/index/hello</span><span class="hljs-regexp">/name/thinkphp</span>
```
```
定義路由后就只能訪問下面的URL地址
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp</span>
```
```
> #### 注意
>
> - - - - - -
>
> 定義路由規則后,原來的URL地址將會失效,變成非法請求。

但這里有一個小問題,如果我們只是訪問
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello</span>
```
```
將發生錯誤,

事實上這是由于路由沒有正確匹配到,我們修改路由規則如下:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 路由參數name為可選</span><span class="hljs-string">'hello/[:name]'</span> => <span class="hljs-string">'index/hello'</span>,
];
```
```
使用`[]`把路由規則中的變量包起來,就表示該變量為可選,接下來就可以正常訪問了。
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello</span>
```
```
當`name`參數沒有傳入值的時候,`hello`方法的`name`參數有默認值`World`,所以輸出的內容為 `Hello,World!`
除了路由配置文件中定義之外,還可以采用動態定義路由規則的方式定義,例如在路由配置文件(`application/route.php`)的開頭直接添加下面的方法:
```
<pre class="calibre18">
```
<span class="hljs-regexp">use</span> <span class="hljs-regexp">think</span>\<span class="hljs-regexp">Route</span>;
<span class="hljs-operator"><span class="hljs-title1">Route</span>:<span class="hljs-string">:<span class="hljs-function">rule</span>(<span class="hljs-operator">'hello/:name'</span>, <span class="hljs-operator">'index/hello'</span>)</span></span>;
```
```
完成的效果和使用配置方式定義是一樣的。
無論是配置方式還是通過Route類的方法定義路由,都統一放到路由配置文件`application/route.php`文件中,具體原因后面會揭曉。
> #### 提示:
>
> - - - - - -
>
> 注意路由配置不支持在模塊配置文件中設置。
## 完整匹配
前面定義的路由是只要以hello開頭就能進行匹配,如果需要完整匹配,可以使用下面的定義:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 路由參數name為可選</span><span class="hljs-string">'hello/[:name]$'</span> => <span class="hljs-string">'index/hello'</span>,
];
```
```
當路由規則以`$`結尾的時候就表示當前路由規則需要完整匹配。
當我們訪問下面的URL地址的時候:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello // 正確匹配</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp // 正確匹配</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp/val/value // 不會匹配</span>
```
```
## 閉包定義
還支持通過定義閉包為某些特殊的場景定義路由規則,例如:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 定義閉包</span><span class="hljs-string">'hello/[:name]'</span> => <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-number">(<span class="hljs-regexp">$name</span>)</span> </span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'!'</span>;
},
];
```
```
或者
```
<pre class="calibre18">
```
<span class="hljs-keyword">use</span> <span class="hljs-title">think</span>\<span class="hljs-title">Route</span>;
Route::rule(<span class="hljs-string">'hello/:name'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-number">(<span class="hljs-regexp">$name</span>)</span> </span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'!'</span>;
});
```
```
> #### 提示:
>
> - - - - - -
>
> 閉包函數的參數就是路由規則中定義的變量。
因此,當訪問下面的URL地址:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp</span>
```
```
會輸出
```
<pre class="calibre18">
```
Hello,thinkphp!
```
```
## 設置URL分隔符
如果需要改變URL地址中的`pathinfo`參數分隔符,只需要在應用配置文件(`application/config.php`)中設置:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 設置pathinfo分隔符</span><span class="hljs-string">'pathinfo_depr'</span> => <span class="hljs-string">'-'</span>,
```
```
路由規則定義無需做任何改變,我們就可以訪問下面的地址:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello-thinkphp</span>
```
```
## 路由參數
我們還可以約束路由規則的請求類型或者URL后綴之類的條件,例如:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 定義路由的請求類型和后綴</span><span class="hljs-string">'hello/[:name]'</span> => [<span class="hljs-string">'index/hello'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>, <span class="hljs-string">'ext'</span> => <span class="hljs-string">'html'</span>]],
];
```
```
上面定義的路由規則限制了必須是`get`請求,而且后綴必須是`html`的,所以下面的訪問地址:
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello // 無效</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello.html // 有效</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp // 無效</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/hello/thinkphp.html // 有效</span>
```
```
> 更多的路由參數請參考完全開發手冊的路由參數一節。
## 變量規則
接下來,我們來嘗試一些復雜的路由規則定義滿足不同的路由變量。在此之前,首先增加一個控制器類如下:
```
<pre class="calibre18">
```
<span class="hljs-operator"><span class="hljs-number"><?php</span><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\<span class="hljs-title">index</span>\<span class="hljs-title">controller</span>;
<span class="hljs-operator"><span class="hljs-keyword">class</span> <span class="hljs-title">Blog</span></span>{
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">get</span><span class="hljs-number">(<span class="hljs-regexp">$id</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'查看id='</span> . <span class="hljs-regexp">$id</span> . <span class="hljs-string">'的內容'</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">read</span><span class="hljs-number">(<span class="hljs-regexp">$name</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'查看name='</span> . <span class="hljs-regexp">$name</span> . <span class="hljs-string">'的內容'</span>;
}
<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">archive</span><span class="hljs-number">(<span class="hljs-regexp">$year</span>, <span class="hljs-regexp">$month</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'查看'</span> . <span class="hljs-regexp">$year</span> . <span class="hljs-string">'/'</span> . <span class="hljs-regexp">$month</span> . <span class="hljs-string">'的歸檔內容'</span>;
}
}</span>
```
```
添加如下路由規則:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-string">'blog/:year/:month'</span> => [<span class="hljs-string">'blog/archive'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'year'</span> => <span class="hljs-string">'\d{4}'</span>, <span class="hljs-string">'month'</span> => <span class="hljs-string">'\d{2}'</span>]],
<span class="hljs-string">'blog/:id'</span> => [<span class="hljs-string">'blog/get'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'id'</span> => <span class="hljs-string">'\d+'</span>]],
<span class="hljs-string">'blog/:name'</span> => [<span class="hljs-string">'blog/read'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w+'</span>]],
];
```
```
在上面的路由規則中,我們對變量進行的規則約束,變量規則使用正則表達式進行定義。
我們看下幾種URL訪問的情況
```
<pre class="calibre18">
```
<span class="hljs-comment">// 訪問id為5的內容</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/blog/5 </span>
<span class="hljs-comment">// 訪問name為thinkphp的內容</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/blog/thinkphp </span>
<span class="hljs-comment">// 訪問2015年5月的歸檔內容</span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/blog/2015/05 </span>
```
```
## 路由分組
上面的三個路由規則由于都是`blog`打頭,所以我們可以做如下的簡化:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-string">'[blog]'</span> => [
<span class="hljs-string">':year/:month'</span> => [<span class="hljs-string">'blog/archive'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'year'</span> => <span class="hljs-string">'\d{4}'</span>, <span class="hljs-string">'month'</span> => <span class="hljs-string">'\d{2}'</span>]],
<span class="hljs-string">':id'</span> => [<span class="hljs-string">'blog/get'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'id'</span> => <span class="hljs-string">'\d+'</span>]],
<span class="hljs-string">':name'</span> => [<span class="hljs-string">'blog/read'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w+'</span>]],
],
];
```
```
對于這種定義方式,我們稱之為路由分組,路由分組一定程度上可以提高路由檢測的效率。
## 復雜路由
有時候,我們還需要對URL做一些特殊的定制,例如如果要同時支持下面的訪問地址
```
<pre class="calibre18">
```
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/blog/thinkphp </span>
<span class="hljs-string">http:</span>
<span class="hljs-comment">//tp5.com/blog-2015-05 </span>
```
```
我們只要稍微改變路由定義規則即可:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-string">'blog/:id'</span> => [<span class="hljs-string">'blog/get'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'id'</span> => <span class="hljs-string">'\d+'</span>]],
<span class="hljs-string">'blog/:name'</span> => [<span class="hljs-string">'blog/read'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w+'</span>]],
<span class="hljs-string">'blog-<year>-<month>'</span> => [<span class="hljs-string">'blog/archive'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'year'</span> => <span class="hljs-string">'\d{4}'</span>, <span class="hljs-string">'month'</span> => <span class="hljs-string">'\d{2}'</span>]],
];
```
```
對 `blog-<year>-<month>` 這樣的非正常規范,我們需要使用`<變量名>`這樣的變量定義方式,而不是 `:變量名`方式。
簡單起見,我們還可以把變量規則統一定義,例如:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 全局變量規則定義</span><span class="hljs-string">'__pattern__'</span> => [
<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w+'</span>,
<span class="hljs-string">'id'</span> => <span class="hljs-string">'\d+'</span>,
<span class="hljs-string">'year'</span> => <span class="hljs-string">'\d{4}'</span>,
<span class="hljs-string">'month'</span> => <span class="hljs-string">'\d{2}'</span>,
],
<span class="hljs-comment">// 路由規則定義</span><span class="hljs-string">'blog/:id'</span> => <span class="hljs-string">'blog/get'</span>,
<span class="hljs-string">'blog/:name'</span> => <span class="hljs-string">'blog/read'</span>,
<span class="hljs-string">'blog-<year>-<month>'</span> => <span class="hljs-string">'blog/archive'</span>,
];
```
```
在`__pattern__`中定義的變量規則我們稱之為全局變量規則,在路由規則里面定義的變量規則我們稱之為局部變量規則,如果一個變量同時定義了全局規則和局部規則的話,當前的局部規則會覆蓋全局規則的,例如:
```
<pre class="calibre18">
```
<span class="hljs-keyword">return</span> [
<span class="hljs-comment">// 全局變量規則</span><span class="hljs-string">'__pattern__'</span> => [
<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w+'</span>,
<span class="hljs-string">'id'</span> => <span class="hljs-string">'\d+'</span>,
<span class="hljs-string">'year'</span> => <span class="hljs-string">'\d{4}'</span>,
<span class="hljs-string">'month'</span> => <span class="hljs-string">'\d{2}'</span>,
],
<span class="hljs-string">'blog/:id'</span> => <span class="hljs-string">'blog/get'</span>,
<span class="hljs-comment">// 定義了局部變量規則</span><span class="hljs-string">'blog/:name'</span> => [<span class="hljs-string">'blog/read'</span>, [<span class="hljs-string">'method'</span> => <span class="hljs-string">'get'</span>], [<span class="hljs-string">'name'</span> => <span class="hljs-string">'\w{5,}'</span>]],
<span class="hljs-string">'blog-<year>-<month>'</span> => <span class="hljs-string">'blog/archive'</span>,
];
```
```
## 生成URL地址
定義路由規則之后,我們可以通過Url類來方便的生成實際的URL地址(路由地址),針對上面的路由規則,我們可以用下面的方式生成URL地址。
```
<pre class="calibre18">
```
<span class="hljs-comment">// 輸出 blog/thinkphp</span>
Url::build(<span class="hljs-string">'blog/read'</span>, <span class="hljs-string">'name=thinkphp'</span>);
Url::build(<span class="hljs-string">'blog/read'</span>, [<span class="hljs-string">'name'</span> => <span class="hljs-string">'thinkphp'</span>]);
<span class="hljs-comment">// 輸出 blog/5</span>
Url::build(<span class="hljs-string">'blog/get'</span>, <span class="hljs-string">'id=5'</span>);
Url::build(<span class="hljs-string">'blog/get'</span>, [<span class="hljs-string">'id'</span> => <span class="hljs-number">5</span>]);
<span class="hljs-comment">// 輸出 blog/2015/05</span>
Url::build(<span class="hljs-string">'blog/archive'</span>, <span class="hljs-string">'year=2015&month=05'</span>);
Url::build(<span class="hljs-string">'blog/archive'</span>, [<span class="hljs-string">'year'</span> => <span class="hljs-string">'2015'</span>, <span class="hljs-string">'month'</span> => <span class="hljs-string">'05'</span>]);
```
```
> #### 提示:
>
> - - - - - -
>
> build方法的第一個參數使用路由定義中的完整路由地址。
我們還可以使用系統提供的助手函數url來簡化
```
<pre class="calibre18">
```
url(<span class="hljs-string">'blog/read'</span>, <span class="hljs-string">'name=thinkphp'</span>);
<span class="hljs-comment">// 等效于</span><span class="hljs-string">Url:</span>:build(<span class="hljs-string">'blog/read'</span>, <span class="hljs-string">'name=thinkphp'</span>);
```
```
> 如果我們的路由規則發生調整,生成的URL地址會自動變化。
如果你配置了`url_html_suffix`參數的話,生成的URL地址會帶上后綴,例如:
```
<pre class="calibre18">
```
<span class="hljs-string">'url_html_suffix'</span> => <span class="hljs-string">'html'</span>,
```
```
那么生成的URL地址 類似
```
<pre class="calibre18">
```
blog/thinkphp.html
blog/<span class="hljs-number">2015</span>/<span class="hljs-number">05.</span>html
```
```
如果你的URL地址全部采用路由方式定義,也可以直接使用路由規則來定義URL生成,例如:
```
<pre class="calibre18">
```
url(<span class="hljs-string">'/blog/thinkphp'</span>);
<span class="hljs-string">Url:</span>:build(<span class="hljs-string">'/blog/8'</span>);
<span class="hljs-string">Url:</span>:build(<span class="hljs-string">'/blog/archive/2015/05'</span>);
```
```
生成方法的第一個參數一定要和路由定義的路由地址保持一致,如果你的路由地址比較特殊,例如使用閉包定義的話,則需要手動給路由指定標識,例如:
```
<pre class="calibre18">
```
<span class="hljs-comment">// 添加hello路由標識</span>
Route::rule([<span class="hljs-string">'hello'</span>,<span class="hljs-string">'hello/:name'</span>], <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-number">(<span class="hljs-regexp">$name</span>)</span></span>{
<span class="hljs-keyword">return</span> <span class="hljs-string">'Hello,'</span>.<span class="hljs-regexp">$name</span>;
});
<span class="hljs-comment">// 根據路由標識快速生成URL</span>
Url::build(<span class="hljs-string">'hello'</span>, <span class="hljs-string">'name=thinkphp'</span>);
<span class="hljs-comment">// 或者使用</span>
Url::build(<span class="hljs-string">'hello'</span>, [<span class="hljs-string">'name'</span> => <span class="hljs-string">'thinkphp'</span>]);
```
```
目前為止,我們掌握的路由功能還只是ThinkPHP`5.0`路由功能的冰山一角,以后我們還會通過更多的專題來講解路由。
## 總結
看完本篇內容后,你應該了解如下的知識:
- URL訪問規范
- 路由定義
- URL地址生成
- 脕茫隆壟脨貌脩脭
- 脕茫隆壟脨貌脩脭
- 脪祿隆壟祿霉麓隆
- 脪祿隆壟祿霉麓隆
- 露鎂隆壟URL潞脥脗路脫脡
- 露鎂隆壟URL潞脥脗路脫脡
- 脠媒隆壟脟毛脟貿潞脥脧矛脫婁
- 脠媒隆壟脟毛脟貿潞脥脧矛脫婁
- 脣脛隆壟脢媒戮脻驢芒
- 脣脛隆壟脢媒戮脻驢芒
- 脦氓隆壟虜茅脩爐脫茂脩脭
- 脦氓隆壟虜茅脩爐脫茂脩脭
- 脕霉隆壟脛攏脨脥潞脥鹿脴脕陋
- 攏簍1攏漏脛攏脨脥露簍脪氓
- 攏簍2攏漏祿霉麓隆虜脵脳梅
- 攏簍3攏漏露脕脠隆脝梅潞脥脨脼賂脛脝梅
- 攏簍4攏漏脌脿脨脥脳陋祿祿潞脥脳脭露爐脥錨魯脡
- 攏簍5攏漏虜茅脩爐路露脦摟
- 攏簍6攏漏脢盲脠毛潞脥脩茅脰隴
- 攏簍7攏漏鹿脴脕陋
- 攏簍8攏漏脛攏脨脥脢盲魯枚
- 脝脽隆壟脢脫脥錄潞脥脛攏擄氓
- 脝脽隆壟脢脫脥錄潞脥脛攏擄氓
- 擄脣隆壟碌梅脢脭潞脥脠脮脰戮
- 擄脣隆壟碌梅脢脭潞脥脠脮脰戮
- 戮脜隆壟API驢陋路壟
- 戮脜隆壟API驢陋路壟
- 脢廬隆壟脙眉脕卯脨脨鹿隴戮脽
- 脢廬隆壟脙眉脕卯脨脨鹿隴戮脽
- 脢廬脪祿隆壟脌漏脮鹿
- 脢廬脪祿隆壟脌漏脮鹿
- 脢廬露鎂隆壟脭脫脧卯
- Cookie
- Session
- 碌樓脭陋虜芒脢脭
- 脥錄脧帽麓婁脌鉚
- 脦脛錄鎂脡脧麓蘆
- 脩茅脰隴脗毛
- 賂陸脗錄
- A隆壟魯攏錄沒脦脢脤芒錄爐
- B隆壟3.2潞脥5.0脟酶鹵冒
- C隆壟脰煤脢脰潞爐脢媒
- 路盧脥芒脝陋攏潞脩摟脧擄ThinkPHP5碌脛脮媒脠路脳脣脢脝
- 路盧脥芒脝陋攏潞脩摟脧擄ThinkPHP5碌脛脮媒脠路脳脣脢脝