laravel-容器
一.作用:容器的作用主要是为了生成,存储实例,解决各种依赖关系
二.例子:如下所示, test需要注入参数$param 并依赖类rely
<?php require 'vendor/autoload.php'; use Illuminate\Container\Container; $container = new Container(); class test { public $param, $rely; public function __construct($param = 'default', rely $rely) { $this->param = $param; $this->rely = $rely; } public function run($runParam) { echo $runParam . PHP_EOL; } } class rely {}
三.调用示例(部分方法是为了实现一些接口类)
(1)make 生成一个实例并自动解决依赖关系
//按默认参数生成test echo $container->make('test')->param . PHP_EOL; //自定义参数 echo $container->make('test', ['param' => 1])->param . PHP_EOL;
(2)when 上下文绑定
//绑定参数 $container->when(['test'])->needs('$param')->give(2); echo $container->make('test')->param . PHP_EOL; //绑定实例 $container->when('test')->needs('rely')->give(function ($app) { $rely = new rely(); $rely->tag = 'by when'; return $rely; }); echo $container->make('test')->rely->tag . PHP_EOL;
(3)自定义方式绑定
$container->bind('test', function($app) { return new test('by bind', new rely); }); echo $container->make('test')->param . PHP_EOL;
ps:关于这几种参数注入的方式 优先级排序 make带参数 > 上下文绑定 > 默认值
(4)bind时$shared设置为true为单例模式(前提是没有传参或者设置上下文)
//bind时$shared设置为true $container->bind('test', function ($app) { return new test('param', new rely); }, true); //修改实例的param, 再去拿是修改后的值 $container->make('test')->param = 1; echo $container->make('test')->param . PHP_EOL; //所有的单例缓存在instances中 call_user_func(\Closure::bind(function () use ($container) { print_r($container->instances); }, null, Container::class));
(5)bound 是否被bind过
echo $container->bound('test') . PHP_EOL; $container->bind('test'); echo $container->bound('test') . PHP_EOL;
(6)has 同bound
echo $container->has('test') . PHP_EOL; $container->bind('test'); echo $container->has('test') . PHP_EOL;
(7)resolved 是否被make过
echo $container->resolved('test') . PHP_EOL; $container->make('test'); echo $container->resolved('test') . PHP_EOL;
(8)isShared 绑定时候$shared是否设置为true
$container->bind('test'); echo $container->isShared('test') . PHP_EOL; $container->bind('test', function ($app) { return new test; }, true); echo $container->isShared('test') . PHP_EOL;
(9)alias 设置别名;isAlias 是否为别名
echo $container->isAlias('test2') . PHP_EOL; $container->alias('test', 'test2'); echo $container->isAlias('test2') . PHP_EOL; echo $container->make('test2')->param;
(10)bindMethod 方法绑定
$container->bindMethod('testMethod', function ($instance, $app) { $app->bind('callBackGivenObj', function($app) use ($instance){ return $instance; }); }); //hasMethodBinding 是否绑定了方法 echo $container->hasMethodBinding('testMethod'); //callMethodBinding 执行之前绑定的方法(绑定了一个名为callBackGivenObj的实例) $container->callMethodBinding('testMethod', new test('callback', new rely)); echo $container->make('callBackGivenObj')->param;
(11)addContextualBinding 增加上下文绑定关系 同when
$container->addContextualBinding('test', '$param', 1); echo $container->make('test')->param; $container->addContextualBinding('test', 'rely', function($app) { $rely = new rely(); $rely->tag = 'by addContextualBinding'; return $rely; }); echo $container->make('test')->rely->tag;
(12)bindIf 如果已经被bind过就不会执行
$container->bind('test', function ($app) { return new test('bind', new rely); }); $container->bindIf('test', function ($app) { return new test('bindIf', new rely); }); echo $container->make('test')->param;
(13)singleton 单例模式绑定 同$this->bind($abstract, $concrete, true)
$container->singleton('test'); $container->make('test')->param = 'change'; echo $container->make('test')->param;
(14)extend 类似装饰着模式 生成实例后会挨个执行extend,存在instances或make过会触发rebound
$container->extend('test', function($instances, $app) { $instances->param = 10; return $instances; }); $container->extend('test', function($instances, $app) { $instances->param += 10; return $instances; }); echo $container->make('test')->param;
(15)instance 直接注入实例缓存 make时直接返回缓存 如果之前bind过会触发rebound
$rely = new rely(); $rely->tag = 'instance'; $container->instance('test', new test('instance', $rely)); echo $container->make('test')->param . PHP_EOL; //有参数会重新生成实例 echo $container->make('test', ['param' => 'other instance cause param'])->param . PHP_EOL; //但上下文绑定不好使了 走的是单例缓存 $container->when('test')->needs('$param')->give('other instance cause when'); echo $container->make('test')->param;
(16)tag 打包 批make
$container->bind('test1', function($app) { return new test('test1', new rely); }); $container->bind('test2', function($app) { return new test('test2', new rely); }); $container->tag(['test1', 'test2'], 'testTag'); $testTags = $container->tagged('testTag'); echo count($testTags) . PHP_EOL; foreach ($testTags as $testObj) { echo $testObj->param . PHP_EOL; }
(17)rebinding 监听到绑定的实例发生更改时执行 可以设置多个 一般有三种情况 重新bind 或者加extend 或者设置instance
$container->bind('test', function ($app) { return new test('test', new rely); }); //$oldInstance 为以当前绑定方式生成的实例 $oldInstance = $container->rebinding('test', function ($app, $instance) { echo ' to ' . $instance->param . PHP_EOL; }); echo 'change ' . $oldInstance->param; //重新绑定 触发rebind $container->bind('test', function ($app) { return new test('test2', new rely); });
(18)refresh 同rebinding 只是把匿名函数的方式改成 class->metohd的方式
class handler { public function deal($instance) { echo ' to ' . $instance->param . PHP_EOL; } } $container->bind('test', function ($app) { return new test('test', new rely); }); $oldInstance = $container->refresh('test', new handler, 'deal'); echo 'change ' . $oldInstance->param; $container->bind('test', function ($app) { return new test('test2', new rely); });
(18)call 执行class->method 第二个参数为带入的参数
$container->call('test@run', ['runParam' => 'byCall1']); $container->call(['test', 'run'], ['runParam' => 'byCall2']); $container->call('test', ['runParam' => 'byCall3'], 'run'); //匿名函数方式 test会自动make $container->call(function (test $test, $otherParam) { $test->run($otherParam); }, ['otherParam' => 'byCall4']); //如果之前被绑定过不会执行test->run 而会执行被绑定的方法 $container->bindMethod('test@run', function ($instance, $app) { echo 'by bindMethod' . PHP_EOL; }); $container->call(['test', 'run'], ['runParam' => 'byCall5']);
(19)wrap 打包一个方法
$closuer = $container->wrap(function(test $test, $param) { echo $param; }, ['param' => 'wrap']); call_user_func($closuer);
(20)factory 打包一个make方法
$closuer = $container->factory('test'); $testInstance = call_user_func($closuer); echo $testInstance->param;
(21)makeWith 同make
(22)get 同make(带不了参数)
(23)build 可以当成纯净版的make(make的下游) 没有那么多乱七八糟的能力(alias, ContextualConcrete, instances, extender等) 只是单纯的解决依赖
(24)resolving resolve的后置钩子
$container->resolving('test', function ($instance, $app) { echo 'make test done' . PHP_EOL; }); $container->make('test'); //单例模式只会在第一次促发 $container->bind('test', 'test', true); $container->make('test'); $container->make('test'); //全局加钩子 $container->resolving(function ($instance, $app) { echo 'done' . PHP_EOL; }); //这里会打印两次done 一次是构建test的时候 一次是构建rely的时候(test的依赖) $container->make('test');
(25)fireResolvingCallbacks 用法同resolving 执行顺序在resolving钩子之后
(26)getBindings 获取bind信息
(27)forgetExtenders 去除之前设置的扩展
$container->extend('test', function($instances, $app) { $instances->param = 10; return $instances; }); echo $container->make('test')->param . PHP_EOL; $container->forgetExtenders('test'); echo $container->make('test')->param . PHP_EOL;
(28)forgetInstance 去除单例
$container->instance('test', new test('instance', new rely)); echo $container->make('test')->param . PHP_EOL; $container->forgetInstance('test'); echo $container->make('test')->param . PHP_EOL;
(29)forgetInstances 去除所有单例
$container->instance('test', new test('instance', new rely)); echo $container->make('test')->param . PHP_EOL; $container->forgetInstances(); echo $container->make('test')->param . PHP_EOL;
(30)flush 全清空 清空内容如下
$this->aliases = []; $this->resolved = []; $this->bindings = []; $this->instances = []; $this->abstractAliases = [];
(31)getInstance 单例模式 返回容器本身
(32)setInstance 设置返回getInstance的实例
(33)offsetExists 同 bound
(34)offsetGet 同 make
(35)offsetSet 同bind 用法有些差异 如下
public function offsetSet($key, $value) { $this->bind($key, $value instanceof Closure ? $value : function () use ($value) { return $value; }); }
(36)offsetUnset 如下
public function offsetUnset($key) { unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]); }