目录
[TOC]
WorkerA 提供了一个简单好用的 IOC 容器 WorkerF\IOCContainer。
IOC 容器是一个特殊的工厂类,它可以帮助你获取你需要的对象,并自动帮你注入需要的依赖 (包括依赖的依赖注入,一直到没有依赖为止)。
IOC 容器提供了单例操作、获取实例、执行实例方法 (给方法注入依赖) 等功能,你可以使用 IOC 容器解决多重依赖的问题,提高开发的效率。
## 单例
设置单例: singleton 方法
```php
use WorkerF\IOCContainer;
...
$a = new A();
IOCContainer::singleton($a);
```
获取单例: getSingleton 方法
```php
// 传入要获取单例的类名
$a = IOCContainer::getSingleton('A');
```
设置单例时还可以指定名称:
```php
$a = new A();
// 设置单例,指定名称
IOCContainer::singleton($a, 'my_singleton');
// 获取单例
$a = IOCContainer::getSingleton('my_singleton');
```
销毁单例:unsetSingleton 方法
```php
// 销毁类 A 的单例
IOCContainer::unsetSingleton('A');
// 再次获取为 null
IOCContainer::getSingleton('A');
```
## 单例注册
IOCContainer 提供了一个 register 方法用来注册单例。和 singleton 方法不同的是,register 方法可以实现自定义类替换抽象类的功能。
这么说可能会难以理解,那么举例说明一下:
```php
// set exception handler
IOCContainer::register(
WorkerF\Exceptions\ExceptionHandler::class,
App\Exceptions\Handler::class
);
```
上述是 bootstrap/boot.php 中设置异常 Handler 的代码。WorkerF\Exceptions\ExceptionHandler::class 在这里算是一个抽象类,是所有异常 Handler 的模板,App\Exceptions\Handler::class 是实际传入的类。即框架获取单例实例时会根据 WorkerF\Exceptions\ExceptionHandler::class 获取,但实际上获取到的是 App\Exceptions\Handler::class 的实例。
这样一来,可以更换自定义 Handler 而又不用改变框架底层代码。
register 方法不传第二个参数时,和 singleton 没有什么区别,只不过 singleton 的参数是实例,register 的参数是类名。
```php
// 只使用默认 ExceptionHandler
IOCContainer::register(WorkerF\Exceptions\ExceptionHandler::class);
```
## 获取实例
IOCContainer 提供了 getInstance 方法来获取一个实例,由 getInstance 方法获取的实例会自动进行依赖注入。
如果注入的实例也有依赖的话,IOC 容器会继续向下查找依赖进行依赖注入,直到所有的依赖注入完成。
例如:
```php
class Foo
{
public $a = 1;
public $b = 2;
}
class Foz
{
public $a = 5;
public $b = 6;
public function __construct(Foo $foo)
{
$this->a = $foo->a + $this->a;
$this->b = $foo->b + $this->b;
}
}
class Bar
{
public $a = 0;
public $b = 0;
public function __construct(Foz $foz)
{
$this->a = $foz->a;
$this->b = $foz->b;
}
}
// 获取 Bar 的实例,IOCContainer 会自动进行依赖注入
$bar = IOCContainer::getInstance(Bar::class);
var_dump($bar->a); // 6
var_dump($bar->b); // 8
```
> 注:1.1.0 版本中 IOCContainer 存在只能注入一层的问题,请升级到 1.1.1 ( 查看 [旧版本升级-小版本升级](旧版本升级.md))。
IOCContainer 还提供了获取实例单例的版本 getInstanceWithSingleton,如果要获取的实例没有设置单例,getInstanceWithSingleton 方法会将该实例设置为单例并返回该实例。
## 方法运行
IOCContainer 的 run 方法用来运行一个实例的方法,并且如果该方法有依赖则进行依赖注入。WorkerA 的路由分发执行控制器方法时就是用的 run 方法。
例子:
```php
class Foo
{
public $a = 1;
public $b = 2;
}
class Bar
{
public function f1(Foo $foo)
{
return $foo->a + $foo->b;
}
}
$result = IOCContainer::run(Bar::class, 'f1'); // result is 3
```
你还可以使用 run 方法的第三个参数给要运行的方法传入额外参数:
```php
class Foo
{
public $a = 1;
public $b = 2;
}
class Bar
{
// 注意额外传入的参数应该在要注入的参数之后
public function f1(Foo $foo, $c, $d)
{
return $foo->a + $foo->b + $c + $d;
}
}
$result = IOCContainer::run(Bar::class, 'f1', [4, 2]); // result is 9
```