thinkphp5URL和路由的功能详解与实例
前⾯的话
本⽂将详细介绍thinkphp5URL和路由
URL访问
ThinkPHP采⽤单⼀⼊⼝模式访问应⽤,对应⽤的所有请求都定向到应⽤的⼊⼝⽂件,系统会从URL参数中解析当前请求的模块、控制器和操作,下⾯是⼀个标准的URL访问格式:
domainName/index.php/模块/控制器/操作
其中index.php就称之为应⽤的⼊⼝⽂件(注意⼊⼝⽂件可以被隐藏,后⾯会提到)
模块在ThinkPHP中的概念其实就是应⽤⽬录下⾯的⼦⽬录,⽽官⽅的规范是⽬录名⼩写,因此模块全部采⽤⼩写命名,⽆论URL是否开启⼤⼩写转换,模块名都会强制⼩写
应⽤的index模块的Index控制器定义如下:
<?php
namespace app\index\controller;
class Index
{
public function index()
{
return 'index';
}
public function hello($name = 'World')
{
return 'Hello,' . $name . '!';
}
}
如果直接访问⼊⼝⽂件的话,由于URL中没有模块、控制器和操作,因此系统会访问默认模块(index)下⾯的默认控制器(Index)的默认操作(index),因此下⾯的访问是等效的:
如果要访问控制器的hello⽅法,则需要使⽤完整的URL地址
访问URL地址后页⾯输出结果为:
Hello,thinkphp!
由于name参数为可选参数,因此也可以使⽤
访问URL地址后页⾯输出结果为:
Hello,World!
默认情况下,URL地址中的控制器和操作名是不区分⼤⼩写的,因此下⾯的访问其实是等效的:
如果控制器是驼峰的,例如定义⼀个HelloWorld控制器(application/index/controller/HelloWorld.php):
<?php
namespace app\index\controller;
class HelloWorld
{
public function index($name = 'World')
{
return 'Hello,' . $name . '!';
}
}
正确的URL访问地址(该地址可以使⽤url⽅法⽣成)应该是
系统会⾃动定位到HelloWorld控制器类去操作
如果使⽤
将会报错,并提⽰Helloworld控制器类不存在
如果希望严格区分⼤⼩写访问(这样就可以⽀持驼峰法进⾏控制器访问),可以在应⽤配置⽂件中设置:
// 关闭URL⾃动转换(⽀持驼峰访问控制器)
'url_convert' => false,
关闭URL⾃动转换之后,必须使⽤下⾯的URL地址访问(控制器名称必须严格使⽤控制器类的名称,不包含控制器后缀):
如果服务器环境不⽀持pathinfo⽅式的URL访问,可以使⽤兼容⽅式,例如:
其中变量s的名称的可以配置的
5.0不再⽀持普通的URL访问⽅式,所以下⾯的访问是⽆效的,你会发现⽆论输⼊什么,访问的都是默认的控制器和操作
参数传⼊
通过操作⽅法的参数绑定功能,可以实现⾃动获取URL的参数,仍然以上⾯的控制器为例,控制器代码如下:
<?php
namespace app\index\controller;
class Index
{
public function index()
{
return 'index';
}
public function hello($name = 'World')
{
return 'Hello,' . $name . '!';
}
}
当我们访问
就是访问app\index\controller\Index控制器类的hello⽅法,因为没有传⼊任何参数,name参数就使⽤默认值World。如果传⼊name参数,则使⽤:
页⾯输出结果为:
Hello,thinkphp!
现在给hello⽅法增加第⼆个参数:
public function hello($name = 'World', $city = '')
{
return 'Hello,' . $name . '! You come from ' . $city . '.';
}
页⾯输出结果为:
Hello,thinkphp! You come from shanghai.
可以看到,hello⽅法会⾃动获取URL地址中的同名参数值作为⽅法的参数值,⽽且这个参数的传⼊顺序不受URL参数顺序的影响,例如下⾯的URL地址输出的结果和上⾯是⼀样的:
还可以进⼀步对URL地址做简化,前提就是我们必须明确参数的顺序代表的变量,我们更改下URL参数的获取⽅式,把应⽤配置⽂件中的url_param_type参数的值修改如下:
// 按照参数顺序获取
'url_param_type' => 1,
页⾯输出结果为:
Hello,thinkphp! You come from shanghai.
页⾯输出结果为:
Hello,shanghai! You come from thinkphp.
显然不是我们预期的结果。
访问也不会得到正确的结果
[注意]按顺序绑定参数的话,操作⽅法的参数只能使⽤URL pathinfo变量,⽽不能使⽤get或者post变量
隐藏⼊⼝
可以去掉URL地址⾥⾯的⼊⼝⽂件index.php,但是需要额外配置WEB服务器的重写规则。
以Apache为例,需要在⼊⼝⽂件的同级添加.htaccess⽂件(官⽅默认⾃带了该⽂件),内容如下
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
如果⽤的phpstudy,规则如下:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
</IfModule>
接下来就可以使⽤下⾯的URL地址访问了
如果使⽤的apache版本使⽤上⾯的⽅式⽆法正常隐藏index.php,可以尝试使⽤下⾯的⽅式配置.htaccess⽂件:
<IfModule mod_rewrite.c>
Options +FollowSymlinks -Multiviews
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?/$1 [QSA,PT,L]
</IfModule>
如果是Nginx环境的话,可以在f中添加:
location / { // …..省略部分代码
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
break;
}
}
定义路由
URL地址⾥⾯的index模块怎么才能省略呢,默认的URL地址显得有点长,下⾯就来说说如何通过路由简化URL访问。
我们在路由定义⽂件(application/route.php)⾥⾯添加⼀些路由规则,如下:
return [
// 添加路由规则路由到 index控制器的hello操作⽅法
'hello/:name' => 'index/index/hello',
];
该路由规则表⽰所有hello开头的并且带参数的访问都会路由到index控制器的hello操作⽅法。
[注意]定义路由规则后,原来的URL地址将会失效,变成⾮法请求。
将发⽣错误
事实上这是由于路由没有正确匹配到,我们修改路由规则如下:
return [
// 路由参数name为可选
'hello/[:name]' => 'index/hello',
];
当name参数没有传⼊值的时候,hello⽅法的name参数有默认值World,所以输出的内容为 Hello,World!
除了路由配置⽂件中定义之外,还可以采⽤动态定义路由规则的⽅式定义,例如在路由配置⽂件(application/route.php)的
开头直接添加下⾯的⽅法:
use think\Route;
Route::rule('hello/:name', 'index/hello');
完成的效果和使⽤配置⽅式定义是⼀样的。
⽆论是配置⽅式还是通过Route类的⽅法定义路由,都统⼀放到路由配置⽂件application/route.php⽂件中[注意]路由配置不⽀持在模块配置⽂件中设置
【完整匹配】
前⾯定义的路由是只要以hello开头就能进⾏匹配,如果需要完整匹配,可以使⽤下⾯的定义:
return [
// 路由参数name为可选
'hello/[:name]$' => 'index/hello',
];
当路由规则以$结尾的时候就表⽰当前路由规则需要完整匹配。
当我们访问下⾯的URL地址的时候:
【闭包定义】
还⽀持通过定义闭包为某些特殊的场景定义路由规则,例如:
return [
// 定义闭包
'hello/[:name]' => function ($name) {
return 'Hello,' . $name . '!';
},
]
;
或者
use think\Route;
Route::rule('hello/:name', function ($name) {
return 'Hello,' . $name . '!';
});
[注意]闭包函数的参数就是路由规则中定义的变量
会输出
Hello,thinkphp!
【设置URL分隔符】
如果需要改变URL地址中的pathinfo参数分隔符,只需要在应⽤配置⽂件(application/config.php)中设置:// 设置pathinfo分隔符
'pathinfo_depr'    => '-',
【路由参数】
还可以约束路由规则的请求类型或者URL后缀之类的条件,例如:
return [
// 定义路由的请求类型和后缀
'hello/[:name]' => ['index/hello', ['method' => 'get', 'ext' => 'html']],
];
上⾯定义的路由规则限制了必须是get请求,⽽且后缀必须是html的,所以下⾯的访问地址:
【变量规则】
接下来,尝试⼀些复杂的路由规则定义满⾜不同的路由变量。在此之前,⾸先增加⼀个控制器类如下:
<?php
namespace app\index\controller;
class Blog
{
public function get($id)
{
return '查看id=' . $id . '的内容';
}
public function read($name)
{
return '查看name=' . $name . '的内容';
}
public function archive($year, $month)
{
return '查看' . $year . '/' . $month . '的归档内容';
}
}
添加如下路由规则:
return [
'blog/:year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
'blog/:id'    => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
'blog/:name'    => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
];
在上⾯的路由规则中,我们对变量进⾏的规则约束,变量规则使⽤正则表达式进⾏定义。
我们看下⼏种URL访问的情况
【路由分组】
上⾯的三个路由规则由于都是blog打头,所以我们可以做如下的简化:
return [
'[blog]' => [
':year/:month' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
':id'    => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
':name'    => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
],
];
对于这种定义⽅式,我们称之为路由分组,路由分组⼀定程度上可以提⾼路由检测的效率
【复杂路由】
有时候,还需要对URL做⼀些特殊的定制,例如如果要同时⽀持下⾯的访问地址
我们只要稍微改变路由定义规则即可:
return [
'blog/:id'      => ['blog/get', ['method' => 'get'], ['id' => '\d+']],
'blog/:name'    => ['blog/read', ['method' => 'get'], ['name' => '\w+']],
'blog-<year>-<month>' => ['blog/archive', ['method' => 'get'], ['year' => '\d{4}', 'month' => '\d{2}']],
];
对 blog-<year>-<month> 这样的⾮正常规范,我们需要使⽤<;变量名>这样的变量定义⽅式,⽽不是 :变量名⽅式。
简单起见,我们还可以把变量规则统⼀定义,例如:
return [
// 全局变量规则定义
'__pattern__'    => [
'name' => '\w+',
'id'  => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
php实例代码详解// 路由规则定义
'blog/:id'      => 'blog/get',
'blog/:name'    => 'blog/read',
'blog-<year>-<month>' => 'blog/archive',
];
在__pattern__中定义的变量规则我们称之为全局变量规则,在路由规则⾥⾯定义的变量规则我们称之为局部变量规则,如果

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。