了解
既然说到是一个新东西,那首先我们就需要了解这到底是一个什么东西
了解的话我们可以看看这篇文章 laravel 学习笔记 —— 神奇的服务容器
理解
这篇文章有一段代码
<?phpclass Container{protected $binds;protected $instances;public function bind($abstract, $concrete){if ($concrete instanceof Closure) {$this->binds[$abstract] = $concrete;} else {$this->instances[$abstract] = $concrete;}}public function make($abstract, $parameters = []){if (isset($this->instances[$abstract])) {return $this->instances[$abstract];}array_unshift($parameters, $this);return call_user_func_array($this->binds[$abstract], $parameters);}}
在看这段代码前,我们需要了解两个东西,一个是闭包,一个是PHP自带的函数call_user_func_array
了解了这两个东西后我们就可以来看看代码了
先定义一个容器类Container,里面定义了两个变量 $binds 和 $instances,前者是 闭包数组(或者是 实例数组)
好了,我们继续往下看,有两个方法,我们先开第一个
<?php
public function bind($abstract, $concrete)
{
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
这个方法是 绑定(或者称为注册)方法,有两个参数 $abstract 和 $concrete,前者是名称key,后者是 闭包 或者是 实例对象
我们可以看到这个方法做了一个判断,判断第二个参数是否是一个闭包,如果是闭包就把闭包放入 $binds 数组, key 为第一个参数,如果不是闭包就放入 $instances 数组,key 也为第一个参数
下面我们来看第二个方法
<?php
public function make($abstract, $parameters = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
这个方法是 生产,也有两个参数 $abstract 和 $parameters,前者是名称key,后者是 参数数组
从上面我们知道 这个方法也做了一个判断,判断名称key是否是实例对象,如果是实例对象的话直接返回出来,如果不是,那么使用 call_user_func_array 函数回调我们存储在 $binds 数组中的闭包函数,array_unshift函数把容器对象放在参数数组中,供回调函数使用
好了,容器类我们看完了,下面我们来粗略的整理一下
服务容器:进化版的工厂模式,用来存储所需接口或者服务的对应实现方式,并且不依赖于外部服务。
绑定:其实就是将接口或者服务的实现方式存储在服务容器中,绑定内容可以是闭包函数,已存在的实例等等。当然在laravel中,绑定的种类更多,几乎可以满足所有的需求。
解析:本质上就是取出我们存储在服务容器中的 对应接口或服务的实现方式。
使用
理解完了后我们来实际操作操作
<?php
//数据库操作类接口
interface Db{
public function remark();
}
//mysql
class MysqlClass implements Db{
public function remark(){
echo '这是操作mysql的类';
}
}
//oracle
class OracleClass implements Db{
public function remark(){
echo '这是操作oracle的类';
}
}
//sql server
class SqlServerClass implements Db{
public function remark(){
echo '这是操作sql server的类';
}
}
//定义一个类
//必须传入一个数据库操作类对象
//数据库操作类必须实现 Db 接口
class My{
public $db;
//定义初始化的类 必须实现 Db 接口
public function __construct(Db $db){
$this->db = $db;
}
}
//容器
class Container{
protected $binds; //存闭包函数
protected $instances; //存实例对象
//绑定 把闭包函数或者实例对象放入数组
public function bind($abstract, $concrete){
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
//生产 执行闭包函数或者返回实例对象
public function make($abstract, $parameters = []){
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
//函数把容器对象放在参数数组中,供回调函数使用
//array_unshift,把值插入数组的开头
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
}
//实例化容器
$container = new Container();
//绑定
$container->bind('MysqlClass',function (){
return new MysqlClass;
});
$container->bind('OracleClass',function (){
return new OracleClass;
});
$container->bind('SqlServerClass',function (){
return new SqlServerClass;
});
//实例化 My 类,并传入 数据库操作类对象
//$my = new My(new MysqlClass);
//$a 是容器对象,也就是上面 make() 方法里面的 array_unshift() 加入的
//$className 是传的参数
$container->bind('My',function ($a,$className){
return new My($a->make($className));
});
//生产
$my = $container->make(My::class,[MysqlClass::class]);
$my->db->remark();
$my = $container->make(My::class,[OracleClass::class]);
$my->db->remark();
$my = $container->make(My::class,[SqlServerClass::class]);
$my->db->remark();
