IOC服务容器

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


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];
}