首页 » PHP » 正文

thinkphp5学习笔记(2)

1、URL访问

http://serverName/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),因此下面的访问是等效的:

http://192.168.0.102/tp5/index.php
http://192.168.0.102/tp5/index.php/index/index/index

如果要访问控制器的hello方法,则需要使用完整的URL地址

http://192.168.0.102/tp5/index.php/index/index/hello
http://192.168.0.102/tp5/index.php/index/index/hello/name/thinkphp //传参

默认情况下,URL地址中的控制器和操作名是不区分大小写的

如果你的控制器是驼峰的,例如定义一个HelloWorld控制器(application/index/controller/HelloWorld.php ):

<?php
namespace app\index\controller;
class HelloWorld
{
public function index($name = 'World')
{
return 'Hello,' . $name . '!';
}
}

正确的方式是 http://192.168.0.102/tp5/index.php/index/hello_world/index

如果使用 http://192.168.0.102/tp5/index.php/index/HelloWorld/index,会报错控制器不存在

如果希望严格区分大小写访问(或者要支持驼峰法进行控制器访问),可以在应用配置文件中设置:

// 关闭URL自动转换(支持驼峰访问控制器)
'url_convert' => false,


如果你的服务器环境不支持 pathinfo 方式的URL访问,可以使用兼容方式,例如:

http://tp5.com/index.php?s=/index/Index/index

——————————————–

2、参数传入

通过操作方法的参数绑定功能,可以实现自动获取URL的参数,仍然以上面的控制器为例,控制器代码如下:

<?php
namespace app\index\controller;
class Index
{
public function index()
{
return 'index';
}
public function hello($name = 'World')
{
return 'Hello,' . $name . '!';
}
}

当我们访问 http://192.168.0.102/tp5/index.php/index/index/hello ,就是访问 app\index\controller\Index 控制器类的 hello 方法,因为没有传入任何参数, name 参数就使用默认值 World 。如果传入name参数,则使用:

http://192.168.0.102/tp5/index.php/index/index/hello/name/thinkphp

页面输出结果为:Hello,thinkphp!

现在给hello方法增加第二个参数:

public function hello($name = 'World', $city = '')
{
return 'Hello,' . $name . '! You come from ' . $city . '.';
}

访问地址:http://192.168.0.102/tp5/index.php/index/index/hello/name/thinkphp/city/weihai
输出:Hello,thinkphp! You come from weihai.

可以看到, hello 方法会自动获取URL地址中的同名参数值作为方法的参数值,而且这个参数的传入顺序不
受URL参数顺序的影响,例如下面的URL地址输出的结果和上面是一样的

http://192.168.0.102/tp5/index.php/index/index/hello/city/weihai/name/thinkphp

或者使用:http://192.168.0.102/tp5/index.php/index/index/hello?city=weihai&name=thinkphp

还可以进一步对URL地址做简化,前提就是我们必须明确参数的顺序代表的变量,我们更改下URL参数的获取
方式,把应用配置文件中的 url_param_type 参数的值修改如下:

    // URL参数方式 0 按名称成对解析 1 按顺序解析
    'url_param_type'         => 1,

现在,URL的参数传值方式就变成了严格按照操作方法的变量定义顺序来传值了,也就是说我们必须使用下面
的URL地址访问才能正确传入 name 和 city 参数到 hello 方法:

http://192.168.0.102/tp5/index.php/index/index/hello/thinkphp/weihai

注意:按顺序绑定参数的话,操作方法的参数只能使用URL pathinfo变量,而不能使用get或者post变量。

———————————————-
3、隐藏index.php

可以去掉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地址访问了

http://192.168.0.102/tp5/index/index/index

如果你使用的 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 环境的话,可以在 Nginx.conf 中添加:

location / { // …..省略部分代码
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=/$1 last;
break;
}
}

注意:我用以上方式均无效,本机环境是apache,在根目录下建立.htaccess文件,内容如下,问题解决:

<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>

—————————————————-

4、定义路由

URL地址里面的 index 模块怎么才能省略呢,默认的URL地址显得有点长,下面就来说说如何通过路由简化
URL访问。
我们在路由定义文件( application/route.php )里面添加一些路由规则,如下:

return [
// 添加路由规则 路由到 index控制器的hello操作方法
'hello/:name' => 'index/index/hello',
];

该路由规则表示所有 hello 开头的并且带参数的访问都会路由到 index 控制器的 hello 操作方法。
路由之前的URL访问地址为:
http://192.168.0.102/index/index/hello/name/thinkphp

定义路由后就只能访问下面的URL地址
http://192.168.0.102/hello/thinkphp

注意:定义路由规则后,原来的URL地址将会失效,变成非法请求。

但这里有一个小问题,如果我们只是访问 http://192.168.0.102/hello 将发生错误,模块不存在。

事实上这是由于路由没有正确匹配到,我们修改路由规则如下:

return [
// 路由参数name为可选
'hello/[:name]' => 'index/hello',
];

使用 [] 把路由规则中的变量包起来,就表示该变量为可选,接下来就可以正常访问了。

除了路由配置文件中定义之外,还可以采用动态定义路由规则的方式定义,例如在路由配置文件(
application/route.php )的开头直接添加下面的方法

use think\Route;
Route::rule('hello/[:name]', 'index/hello');

完成的效果和使用配置方式定义是一样的。
无论是配置方式还是通过Route类的方法定义路由,都统一放到路由配置文件 application/route.php
文件中,具体原因后面会揭晓。

—————————————————-

5、完整匹配

前面定义的路由是只要以hello开头就能进行匹配,如果需要完整匹配,可以使用下面的定义:

return [
// 路由参数name为可选
'hello/[:name]$' => 'index/hello',
];

当路由规则以 $ 结尾的时候就表示当前路由规则需要完整匹配。
当我们访问下面的URL地址的时候:

http://192.168.0.102/hello //正确匹配
http://192.168.0.102/hello/thinkphp //正确匹配
http://192.168.0.102/hello/thinkphp/val/value //不会匹配

————————————————————

6、闭包定义

还支持通过定义闭包为某些特殊的场景定义路由规则,例如:

return [
// 定义闭包
'hello/[:name]' => function ($name) {
return 'Hello,' . $name . '!';
},
];

或者

use think\Route;
Route::rule('hello/:name', function ($name) {
return 'Hello,' . $name . '!';
});
注意:闭包函数的参数就是路由规则中定义的变量。

因此,当访问下面的URL地址:http://192.168.0.102/hello 会输出Hello,thinkphp

注:此处有问题,待修正。

—————————————————————

7、设置URL分隔符

如果需要改变URL地址中的 pathinfo 参数分隔符,只需要在应用配置文件(
application/config.php )中设置:

// 设置pathinfo分隔符
'pathinfo_depr' => '-',

如http://192.168.0.102/index-index-index

——————————————————————-
8、路由参数

我们还可以约束路由规则的请求类型或者URL后缀之类的条件,例如:

return [
// 定义路由的请求类型和后缀
'hello/[:name]' => ['index/hello', ['method' => 'get', 'ext' => 'html']],
];

上面定义的路由规则限制了必须是 get 请求,而且后缀必须是 html 的,所以下面的访问地址:

http://192.168.0.102/hello //无效
http://192.168.0.102/hello.html //有效
http://192.168.0.102/hello/thinkphp //无效
http://192.168.0.102/hello/thinkphp.html //有效

——————————————————————–

9、变量规则

接下来,我们来尝试一些复杂的路由规则定义满足不同的路由变量。在此之前,首先增加一个控制器类如
下:

<?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访问的情况

http://192.168.0.102/blog/8 //查看id=8的内容
http://192.168.0.102/blog/thinkphp //查看name=thinkphp的内容
http://192.168.0.102/blog/2016/12 //查看2016/12的归档内容

——————————————————————–

10、路由分组

上面的三个路由规则由于都是 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+']],
],
];

对于这种定义方式,我们称之为路由分组,路由分组一定程度上可以提高路由检测的效率。

——————————————————————–

11、复杂路由

有时候,我们还需要对URL做一些特殊的定制,例如如果要同时支持下面的访问地址
http://192.168.0.102/blog/thinkphp
http://192.168.0.102/blog-2016-12

我们只要稍微改变路由定义规则即可:

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- 这样的非正常规范,我们需要使用 <变量名> 这样的变量定义方式,而不是:变量名 方式。
简单起见,我们还可以把变量规则统一定义,例如:

return [
// 全局变量规则定义
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
// 路由规则定义
'blog/:id' => 'blog/get',
'blog/:name' => 'blog/read',
'blog-<year>-<month>' => 'blog/archive',
];

在 __pattern__ 中定义的变量规则我们称之为全局变量规则,在路由规则里面定义的变量规则我们称之为
局部变量规则,如果一个变量同时定义了全局规则和局部规则的话,当前的局部规则会覆盖全局规则的,例
如:

return [
// 全局变量规则
'__pattern__' => [
'name' => '\w+',
'id' => '\d+',
'year' => '\d{4}',
'month' => '\d{2}',
],
'blog/:id' => 'blog/get',
// 定义了局部变量规则
'blog/:name' => ['blog/read', ['method' => 'get'], ['name' => '\w{5,}']],
'blog-<year>-<month>' => 'blog/archive',
];

——————————————————————–

12、生成url地址

定义路由规则之后,我们可以通过Url类来方便的生成实际的URL地址(路由地址),针对上面的路由规则,
我们可以用下面的方式生成URL地址。

// 输出 blog/thinkphp
Url::build('blog/read', 'name=thinkphp');
Url::build('blog/read', ['name' => 'thinkphp']);
// 输出 blog/5
Url::build('blog/get', 'id=5');
Url::build('blog/get', ['id' => 5]);
// 输出 blog/2015/05
Url::build('blog/archive', 'year=2015&month=05');
Url::build('blog/archive', ['year' => '2015', 'month' => '05']);
注意:build方法的第一个参数使用路由定义中的完整路由地址。

我们还可以使用系统提供的助手函数url来简化

url('blog/read', 'name=thinkphp');
// 等效于
Url::build('blog/read', 'name=thinkphp');
注意:如果我们的路由规则发生调整,生成的URL地址会自动变化

如果你配置了 url_html_suffix 参数的话,生成的URL地址会带上后缀,例如:

‘url_html_suffix’ => ‘html’,

那么生成的URL地址 类似

blog/thinkphp.html
blog/2015/05.htm

如果你的URL地址全部采用路由方式定义,也可以直接使用路由规则来定义URL生成,例如

url('/blog/thinkphp');
Url::build('/blog/8');
Url::build('/blog/archive/2015/05')

生成方法的第一个参数一定要和路由定义的路由地址保持一致,如果你的路由地址比较特殊,例如使用闭包
定义的话,则需要手动给路由指定标识,例如:

// 添加hello路由标识
Route::rule(['hello','hello/:name'], function($name){
return 'Hello,'.$name;
});
// 根据路由标识快速生成URL
Url::build('hello', 'name=thinkphp');
// 或者使用
Url::build('hello', ['name' => 'thinkphp']);
博主的文章或程序如果给您带来了价值,感谢您打赏一二
微信扫码支付 支付宝扫码支付

发表评论