一.作用:容器的作用主要是为了生成,存储实例,解决各种依赖关系

 

   二.例子:如下所示, 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]);
}