容器和依赖注入
依赖注入
- 手册对依赖注入比较严谨的说明,具体如下:
依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于URL请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成.
- 先看一个小例子,了解一下依赖注入的写法,创建一个模型;
namespace app\model;
use think\Model;
class One extends Model
{
public $username = 'Mr.Lee';
}
- 创建一个控制器
Inject
,通过依赖注入将模型One
对象引入其内;
namespace app\controller;
use app\model\One;
class Inject
{
protected $one;
public function __construct(One $one)
{
$this->one = $one;
}
public function index()
{
return $this->one->username;
}
}
- 依赖注入:即允许通过类的方法传递对象的能力,并且限制了对象的类型(约束);
- 而传递的对象背后的那个类被自动绑定并且实例化了,这就是依赖注入;
容器
- 依赖注入的类统一由容器管理的,大多数情况下是自动绑定和自动实例化的;
- 如果想手动来完成绑定和实例化,可以使用
bind()
和app()
助手函数来实现;
class Inject
{
public function index()
{
bind('one', 'app\model\One');
return app('one')->username;
}
}
bind('one','...')
绑定类库标识,这个标识具有唯一性,以便快速调用;app('one')
快速调用,并自动实例化对象,标识严格保持一致包括大小写;- 自动实例化对象的方式,是采用单例模式实现,如果想重新实例化一个对象,则:
//每次调用总是会重新实例化
bind('one', 'app\model\One');
$one = app('one',[], true);
return $one->username;
app('one',[])
中第二参数,方法实例化对象的时候,传递参数;
bind('one', 'app\model\One');
$one = app('one', [['file']], true);
return $one->username;
- 当然,你也可以直接通过
app()
绑定一个类到容器中并自动实例化;
return app('app\model\One')->username;
- 使用
bind([])
可以实现批量绑定,只不过系统有专门提供批量绑定的文件;
bind(['one' => 'app\model\One','user' => 'app\model\User']);
return app('one')->username;
bind(['one' => \app\model\One::class,'user' => \app\model\User::class]);
return app('one')->username;
::class
模式,不需要单引号,而且需要在最前面加上\\
,之前的加不加都行;- 系统提供了
provider.php
文件,用于批量绑定类到容器中,这里不加不报错;
return [
'one' => app\model\One::class, //这里加不加\都正常
'user' => app\model\User::class
];
- 系统内置了很多常用的类库,以便开发者快速调用,具体如下:
- 也就是说,实现同一个效果可以由容器的
bind()
和app()
实现,也可以使用依赖注入实现,还有Facade
实现,以及助手函数实现;
门面Facade
创建静态调用
Facade
即门面设计模式,为容器的类提供了一种静态的调用方式;- 在之前的很多课程中,我们大量的引入
Facade
类库,并且通过静态调用; - 比如请求
Request::?
,路由Route::?
,数据库Db::?
等等,均来自Facade
; - 下面我们手工来创建一个自己的静态调用类库,来了解一下流程;
- 首先,在应用目录下创建
common
公共类库文件夹,并创建Test.php
;
namespace app\common;
class Test
{
public function hello($name)
{
return 'Hello, '.$name;
}
}
- 再在同一个目录下创建
facade
文件夹,并创建Test.php
,用于生成静态调用;
namespace app\facade;
use think\Facade;
class Test extends Facade
{
protected static function getFacadeClass()
{
return 'app\common\Test';
}
}
- 然后在控制器端,就可以和之前系统提供的静态调用一样调用了;
return Test::hello('Mr.Lee!');
核心类库
- 以下是系统提供的常用 Facade 核心类库表;
请求对象和信息
请求对象
- 使用构造方法注入请求,如下:
namespace app\controller;
use think\Request;
class Rely
{
protected $request;
public function __construct(Request $request)
{
$this->request = $request;
}
public function index()
{
return $this->request->param('username');
}
}
Request
请求对象拥有一个param
方法,传入参数username
,可以得到相应的值;- 也可以在普通方法下直接使用,如下:
use think\Request;
class Rely
{
public function index(Request $request)
{
return $request->param('username');
}
}
- 使用
Facade
方式应用于没有进行依赖注入时使用Request
对象的场合;
use think\facade\Request;
class Rely
{
public function index()
{
return Request::param('username');
}
}
- 使用助手函数
request()
方法也可以应用在没有依赖注入的场合;
class Rely
{
public function index()
{
return request()->param('username');
}
}
请求信息
Request
对象除了param
方法外,还有一些请求的固定信息,如表:
- 上表的调用方法,直接调用即可,无须传入值,只有极个别如果传入
true
获取完整URL的功能;
// 获取完整 URL 地址 不带域名
Request::url();
// 获取完整 URL 地址 包含域名
Request::url(true);
// 获取当前 URL(不含 QUERY_STRING) 不带域名
Request::baseFile();
// 获取当前 URL(不含 QUERY_STRING) 包含域名
Request::baseFile(true);
// 获取 URL 访问根地址 不带域名
Request::root();
// 获取 URL 访问根地址 包含域名
Request::root(true);
- 还可以获取当前控制器和操作方法的名称:
::controller()
和::action()
;
return Request::controller().'|'.Request::action();
请求变量
请求变量
Request
对象支持全局变量的检测,
获取和安全过滤,支持$_GET
,$_POST
等;- 为了方便演示,这里一律使用
Facade
的静态调用模式; - 使用
has()
方法,可以检测全局变量是否已经设置:
Request::has('id', 'get');
Request::has('username', 'post');
Request
支持的所有变量类型方法,如下表:
param()
变量方法是自动识别GET
,POST
等的当前请求,推荐使用;
//获取请求为 name 的值,过滤
Request::param('name');
//获取所有请求的变量,以数组形式,过滤
Request::param();
//获取所有请求的变量(原始变量),不包含上传变量,不过滤
Request::param(false);
//获取部分变量
Request::param(['name','age']);
- 默认情况下,并没有配置字符过滤器,可在
app\Request.php
配置;
protected $filter = ['htmlspecialchars'];
- 如果没有设置字符过滤器,或者局部用别的字符过滤器,可以通过第三参数;
Request::param('name', '', 'htmlspecialchars');
Request::param('name', '', 'strip_tags,strtoupper');
- 如果设置了全局字符过滤器,但又不想某个局部使用,可以只用 null 参数;
Request::param('name', '', null);
- 如果获取不到值,支持请求的变量设置一个默认值;
Request::param('name', '默认值');
- 如果采用的是路由URL,也可以获取到变量,但
param::get()
不支持路由变量;
Request::param('id');
Request::route('id');
Request::get('id'); //路由参数,get 获取不到
- 使用 only()方法,可以获取指定的变量,也可以设置默认值;
Request::only(['id','name']);
Request::only(['id'=>1,'name'=>'默认值']);
- 使用 only()方法,默认是 param 变量,可以在第二参数设置
GET
,POST
等;
Request::only(['id','name'], 'post');
- 相反的 except()方法,就是排除指定的变量;
Request::except(['id','name']);
Request::except(['id'=>1,'name'=>'默认值']);
Request::except(['id','name'], 'post');
- 使用变量修饰符,可以将参数强制转换成指定的类型;
/s(字符串)
,/d(整型)
,/b(布尔)
,/a(数组)
,/f(浮点)
;
Request::param('id/d');
助手函数
- 为了简化操作,Request 对象提供了助手函数;
input('?get.id'); //判断 get 下的 id 是否存在
input('?post.name'); //判断 post 下的 name 是否存在
input('param.name'); //获取 param 下的 name 值
input('param.name', '默认值'); //默认值
input('param.name', '', 'htmlspecialchars'); //过滤器
input('param.id/d'); //设置强制转换
请求类型和HTTP头信息
请求类型
- 有时,我们需要判断
Request
的请求类型,比如GET
,POST
等等; - 可以使用
method()
方法来判断当前的请求类型,当然,还有很多专用的请求判断; - 使用普通表单提交,通过
method()
方法获取类型;
$html = <<<EOF
<form action="http://tp6/datatest" method="post">
<input type="text" name="name" value="Lee">
<input type="submit" value="提交">
</form>
EOF;
echo $html;
return Request::method();
- 在表单提交时,我们也可以设置请求类型伪装,设置隐藏字段
_method
; - 而在判断请求,使用
method(true)
可以获取原始请求,否则获取伪装请求;
<input type="hidden" name="_method" value="PUT">
Request::method(true);
- 伪装请求
- 原始请求
- 如果想更改请求伪装变量类型的名称,可以在
app/Request.php
中更改;
protected $varMethod = '_m';
AJAX/PJAX
伪装,使用?_ajax=1
和?_pjax=1
,并使用isAjax()
和isPjax()
;
$html = <<<EOF
<form action="http://tp6/datatest?_ajax=1" method="post">
<input type="text" name="name" value="Lee">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="提交">
</form>
EOF;
echo $html;
dump(Request::isAjax());
- 这里需要用
isAjax()
和isPjax()
来判断,用method
无法判断是否为a(p)jax
; - 在
app.php
也可以更改ajax
和pjax
的名称;
protected $varAjax = '_a';
protected $varPjax = '_p';
HTTP头信息
- 使用
header()
方法可以输出HTTP头信息,返回是数组类型,也可单信息获取;
Request::header();
Request::header('host');
伪静态,参数绑定,请求缓存
伪静态
- 可以通过
route.php
修改伪静态的后缀,比如修改成shtml
,xml
等;
'url_html_suffix' => 'html',
- 如果地址栏用后缀访问成功后,可以使用
Request::ext()
方法得到当前伪静态;
return Request::ext();
- 配置文件伪静态后缀,可以支持多个,用竖线隔开;
'url_html_suffix' => 'shtml|xml|pdf',
- 直接将伪静态配置文件设置为
false
,则关闭伪静态功能;
'url_html_suffix' => false,
参数绑定
- 参数绑定功能:即URL地址栏的数据传参,我们一直在使用的功能;
public function get($id)
{
return 'get:'.$id;
}
- 操作方法URL:
/get
,而带上id
参数后,则为:/get/id/5
; - 如果缺少了
/5
或者缺少了/id/5
,则都会报错方法参数错误:id
; - 那么解决方案,就是给
$id = 0
一个默认值,防止URL参数错误; - 如果设置了两个参数,那么参数传递的执行顺序可以设置,比如;
public function get($id, $name)
{
return 'get:'.$id.','.$name;
}
- 不管是:
/id/5/name/lee
,还是:/name/lee/id/5
,都不会产生错误;
请求缓存
- 请求缓存仅对GET请求有效,可以在全局和局部设置缓存;
- 如果要设置全局请求缓存,在中间件文件
middleware.php
中设置;
'think\middleware\CheckRequestCache',
- 然后在
route.php
中设置缓存的声明周期即可;
'request_cache_expire' => 3600,
- 当第二次访问时,会自动获取请求缓存的数据响应输出,并发送304状态码;
- 如果要对路由设置一条缓存,直接使用
cache(3600)
方法;
Route::get('get/:id', 'Rely/get')->cache(3600);
响应输出和重定向
响应操作
- 响应输出,有好几种:包括
return
,json()
和view()
等等; - 默认输出方式是以html格式输出,如果你发起json请求,则输出json;
- 而背后是
response
对象,可以用response()
输出达到相同的效果;
return response($data);
- 使用
response()
方法可以设置第二参数,状态码,或调用code()
方法;
return response($data, 201);
return response($data)->code(202);
- 使用
json()
,view()
方法和response()
返回的数据类型不同,效果一样;
return json($data, 201);
return json($data)->code(202);
- 不但可以设置状态码,还可以设置
header()
头文件信息;
return json($data)->code(202)->header(['Cache-control' => 'no-cache,must-revalidate']);
重定向
- 使用
redirect()
方法可以实现页面重定向,需要return
执行;
return redirect('http://www.baidu.com');
- 站内重定向,直接输入路由地址或相对地址即可,第二参数状态码;
return redirect('ds/5');
return redirect('/address/details/id/5', 201);
- 使用
url
自动生成跳转地址,普通地址或路由地址;
return redirect(url('address/index'));
- 附加
session
信息,并跳转重定向;
return redirect(url('address/index'))->with('name', 'Mr.Lee');
- 重定向还提供了,记住上一次的url,和跳转到上一次url的功能;
// 记住当前url后跳转
return redirect()->remember();
// 跳转到上次记住的url
return redirect()->restore();
最后一次更新于2020-08-04 16:07
0 条评论