新建container
laravel框架public目录下新建container.php,先建立user和log两个类供后续,实例化容器
/**
* @author biny
* @date 2021-08-11 8:45
*/
require __DIR__.'/../vendor/autoload.php';
use Illuminate\Container\Container;
class User
{
public $param;
public $log;
public function __construct($param = Null, Log $log)
{
$this->param = $param;
$this->log = $log;
}
public static function run($runParam)
{
return $runParam;
}
}
class Log
{
}
$container = new Container();
方法名 | 描述 | 调用方法 |
---|---|---|
make | 生成一个实例并自动解决依赖关系 | $container->make( $abstract, array $parameters = []) |
bind | 绑定方法 | $container->bind(Transistor::class, function( $app) { //… }); |
bound | 是否被bind过 | $container->bound( $abstract) |
has | 等同bound | $container->has( $abstract) |
resolved | 是否被make过 | $container->resolved( $abstract) |
alias | 设置别名 | $container->alias( $abstract, $alias) |
isAlias | 是否为别名 | $container->isAlias( $name) |
build | 最简版的能解决DI注入的IOC容器 | $container->build( $concrete) |
bind 绑定方法
bind bindIf 已resolved解析过的,再次bind会rebound
//绑定一个服务容器
$container->bind('user', function ($app) {
return new User('bind', new Log);
});
echo $container->user->param; # 输出bind
//判断是否绑定,上面已绑定过,这次绑定操作被忽略,不会执行
$container->bindIf('user', function ($app) {
return new User('bindIf', new Log);
});
echo $container->user->param; # 输出bind,而不是bindIf
singleton单例
singleton单例模式绑定,仅绑定一次,不会重复绑定
$container->singleton('user'); # 绑定user类
$container->make('user')->param = 'change'; # 设置参数
$container->make('user')->log->tag = 'tag'; # 设置参数
echo $container->user->param; # 访问方式一
echo $container['user']->log->tag; # 访问方式二
instance 注册实例
instance 注册实例缓存 make时直接返回注册内容 如果之前bind过会触发rebound
$container->instance('user', new User('param', new log));
echo $container->user->param;.PHP_EOL; # param
//有参数会重新生成实例
echo $container->make('user', ['param' => 'new param'])->param.PHP_EOL; # new param
//上下文绑定无效 instance是单例缓存
$container->when('user')->needs('$param')->give('new param with when');
echo $container->make('user')->param; # param
extend 绑定扩展
extend 生成实例后会依次执行绑定的extend
$container->extend('user', function($instances, $app) {
$instances->param = 1;
return $instances;
});
$container->extend('user', function($instances, $app) {
$instances->param += 2;
return $instances;
});
echo $container->make('user')->param;//输出3
tag 标签
tag 按类别给多个服容器者打标签 tagged逐个make
$container->bind('user1', function($app) {
return new User('user1', new Log);
});
$container->bind('user2', function($app) {
return new User('user2', new Log);
});
$container->tag(['user1', 'user2'], 'userTags');
$userTags = $container->tagged('userTags');
echo 'count:'.count($userTags) . PHP_EOL;
foreach ($userTags as $obj) {
echo $obj->param . PHP_EOL;
}
resolving 钩子
resolving resolve的后置钩子
$container->resolving('user', function ($instance, $app) {
echo 'make user done' . PHP_EOL;
});
$container->make('user');
//单例模式只会在第一次促发
$container->bind('user', 'user', true);
$container->make('user');
$container->make('user');
//全局钩子
$container->resolving(function ($instance, $app) {
echo 'make done' . PHP_EOL;
});
//这里会打印两次make done 一次是构建user 一次是构建log(user的依赖)
$container->make('user');
refresh 监听
refresh 监听绑定的实例发生更改时执行,等同rebinding ,把匿名函数的方式改成 class->metohd的方式
class handler {
public function deal($instance) {
echo ' change to ' . $instance->param . PHP_EOL;
}
}
$container->bind('user', function ($app) {
return new User('user', new Log);
});
echo $container->make('user')->param;
$oldInstance = $container->refresh('user', new handler, 'deal');
$container->bind('user', function ($app) {
return new User('user2', new Log);
});
rebinding 监听
rebinding 监听绑定的实例发生更改时执行 可以设置多个 一般有三种情况 重新bind 或者加extend 或者设置instance
$container->bind('user', function ($app) {
return new User('user', new Log);
});
//$oldInstance 为以当前绑定方式生成的实例
$oldInstance = $container->rebinding('user', function ($app, $instance) {
echo ' to ' . $instance->param . PHP_EOL;
});
echo 'change ' . $oldInstance->param;
//重新绑定 触发rebind
$container->bind('user', function ($app) {
return new User('user2', new Log);
});
call 执行class->method
call 执行class->method 第二个参数为带入的参数
echo $container->call('User@run', ['runParam' => 'user1']).PHP_EOL;
echo $container->call(['User', 'run'], ['runParam' => 'user2']).PHP_EOL; # 需要静态方法
echo $container->call('User', ['runParam' => 'user3'], 'run').PHP_EOL;
//匿名函数方式 test会自动make
$container->call(function (User $user, $otherParam) {
echo $user->run($otherParam).PHP_EOL;
}, ['otherParam' => 'user4']);
bindMethod 绑定方法
bindMethod:绑定方法 不能重复绑定
$container->bindMethod('testMethod', function ($instance, $app) {
$app->bind('callBackUser', function($app) use ($instance){
return $instance;
});
});
//hasMethodBinding 判断是否绑定了方法
echo $container->hasMethodBinding('testMethod');
//callMethodBinding 执行之前绑定的方法(bind callBackUser)
$container->callMethodBinding('testMethod', new User('param_value', new log));
echo 'class User->param:'.$container->make('callBackUser')->param.PHP_EOL;
//make的简写,使用offsetGet方法
echo 'class User->run:'.$container['callBackUser']->run('run_value').PHP_EOL;
addContextualBinding
addContextualBinding绑定上下文
$container->addContextualBinding('User', '$param', 'param_value');
$container->addContextualBinding('User', 'Log', function($app) {
$log = new Log();
$log->tag = 'by addContextualBinding';
return $log;
});
echo '$param:'.$container['User']->param.PHP_EOL;
echo 'class User->run:'.$container['User']->run('run_value').PHP_EOL;
echo 'class Log->tag:'.$container['User']->log->tag.PHP_EOL;
wrap 打包
wrap 打包一个方法
$closuer = $container->wrap(function(User $user, $param) {
echo $param;
}, ['param' => 'wrap']);
call_user_func($closuer);
factory打包
factory打包 一个make方法
$closure = $container->factory('user');
$userInstance = call_user_func($closure);
$userInstance->param = 'user';
echo $userInstance->param;
forget清除系列
$container->forgetExtenders('user'); # forgetExtenders 清除扩展extend
$container->forgetInstance('user'); # forgetInstance 清除单例
$container->forgetInstances(); # forgetInstances 清除所有单例
$container->flush(); # 清除$this->aliases = []; $this->resolved = []; $this->bindings = []; $this->instances = []; $this->abstractAliases = [];
ArrayAccess接口
isset($container['user']); #调用 offsetExists($key) 等同 bound
$container['user']; # 调用 offsetGet($key) 等同 make
$container['user']->param = 'new param'; # 调用 offsetSet($key, $value) 等同 bind仅限传入闭包方式,非闭包打包成闭包传入bind($key, $value)
unset($container['user']); # 调用offsetUnset($key) 等同 unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);