IOC 服务容器

发布于 2021-12-27  1353 次阅读


IOC 即控制反转(Inversion of Control)关于其基础解释,网上大多都有(大多都是一些不明不白的例子)。本文不再赘述。这里我们从代码的角度来说一说 IOC 容器(以 PHP 为例)

IOC 的实质是一个超级工厂类,目的是为了解耦

先说一说最基本的 IOC 容器有什么

  • bind
  • make
可以把 IOC 容器想象成一个箱子

bind

protected $binds;
protected $instances;

public function bind($abstract, $concrete): void
{
    if ($concrete instanceof Closure) {
        $this->binds[$abstract] = $concrete;
    } else {
        $this->instances[$abstract] = $concrete;
    }
}

bind 的作用就是将物品放入箱子,本质是告诉工厂这个类要怎么做出来
所以在实际的使用中,你能看见它能绑定很多东西,比如绑定至接口,绑定至匿名函数,绑定至别名等等
bind 比较简单,在此不再解释


make

public function make($abstract, array $parameters = []): mixed
{
    try {
        $reflector = new ReflectionClass($abstract);
    } catch (ReflectionException $e) {
        throw new ReflectionException($e);
    }
    $constructor = $reflector->getConstructor();

    $args = [];
    if ($constructor) {
        foreach ($constructor->getParameters() as $param) {
            $class = $param->getType();
            assert($class instanceof ReflectionNamedType);
            if ($class) {
                $args[] = $this->make($class->getName());
            }
        }
    }

    $args = array_merge($args, $parameters);

    return $reflector->newInstanceArgs($args);
}

make 的作用是实例化一个类
make 有些复杂,接下来详细说说

有的时候一个类依赖其他类,依赖的类又依赖别的类,这会导致实例化的时候异常麻烦,make 正是为了解决类的相互依赖而设计的

ReflectionClass 是一个 php 的反射类,此类报告了一个类的有关信息


解释

既然要实例化一个类,那必然就要获取类的构造函数即 getConstructor()方法,如果这个类有构造函数那么便获取它的参数 getParameters(),去迭代这个参数,获取参数类型 getType(),从中获取要被实例化的这个类的依赖,如果还有依赖,那么便递归,最后合并这个参数和类,从给出的参数创建一个新的类实例 newInstanceArgs($args)


更多

自 PHP7.1.0 起,ReflectionType::__toString()已弃用 ReflectionParameter::getType()可能会返回 ReflectionNamedType 的实例。要获取参数类型的名称,在这种情况下可以使用 ReflectionNamedType()
例如:

function someFunction(int $param, $param2) {}

$reflectionFunc = new ReflectionFunction('someFunction');
$reflectionParams = $reflectionFunc->getParameters();
$reflectionType1 = $reflectionParams[0]->getType();
$reflectionType2 = $reflectionParams[1]->getType();

echo $reflectionType1, PHP_EOL;
var_dump($reflectionType2);

自 PHP8.0.0 起,此方法可能会返回一个 ReflectionNamedType 实例或一个 ReflectionUnionType 实例。后者是前者的集合。为了分析一个类型,将它规范化为一个 ReflectionNamedType 对象数组通常很方便。
例如:

function getAllTypes(ReflectionParameter $reflectionParameter): array
{
    $reflectionType = $reflectionParameter->getType();

    if (!$reflectionType) return [];

    return $reflectionType instanceof ReflectionUnionType
        ? $reflectionType->getTypes()
        : [$reflectionType];
}