EasySwoole容器DI组件源码剖析

EasySwoole的DI容器实现相对简单,我们可以通过以下方法setget操作类或闭包,甚至是一段字符串.

class Test
{
    public function testA() {
        return "test";
    }
}

Di::getInstance()->set('DI_NUMBER', 5000); // 将5000这个整数存入容器中
Di::getInstance()->set('DI_CLASS', Test::class); // 把类存入容器
Di::getInstance()->set('DI_CALLABLE', function($a) {
    return $a;
}); // 将这个可执行的闭包存入容器


var_dump(Di::getInstance()->get('DI_NUMBER')); // 5000
var_dump(Di::getInstance()->get('DI_CLASS')->testA()); // test 
var_dump(Di::getInstance()->get('DI_CALLABLE')("this is callable")); // this is callable

下面我们来看看底层如何实现的,类在Vendor/easyswoole/component/src/Di.php

class Di
{
    use Singleton;
    private $container = array(); // 会将set进的数据保存在容器里.
    ...
}

需要注意的是Di容器在Swoole服务创建后修改里面的数据会仅针对当前进程有效.如果需要跨进程可以利用SwooleTable.

来接着看下set方法,仅单纯将数据存入container数组中.$obj没有做任何限制.

public function set($key, $obj,...$arg):void
{
    $this->container[$key] = array(
        "obj"=>$obj,
        "params"=>$arg,
    );
}

下面看看get方法.如果存入的obj是对象或者闭包直接返回,存入的是类的话会去尝试实例化它,并存入容器方便下次直接返回对象.

function get($key)
{
    // 首先判断是否存在key
    if (isset($this->container[$key])) {
        $obj = $this->container[$key]['obj'];
        $params = $this->container[$key]['params'];
        
        // 判断obj是否为对象或者可调用的方法
        if (is_object($obj) || is_callable($obj)) {
            return $obj;
        } else if (is_string($obj) && class_exists($obj)) {
            try {
                // 如果是一个类,则去实例化它
                $this->container[$key]['obj'] = new $obj(...$params);
                return $this->container[$key]['obj'];
            } catch (\Throwable $throwable) {
                throw $throwable;
            }
        } else {
            return $obj;
        }
    } else {
        return null;
    }
}

剩下还有两个cleardelete方法.就不用我过多介绍了.

function delete($key): void
{
    unset($this->container[$key]);
}

function clear(): void
{
    $this->container = array();
}

总体EasySwoole的容器类实现较为轻量,使用起来足够简单.


Revision #2
Created Wed, Jan 8, 2020 11:54 AM by 小黄
Updated Fri, Jan 10, 2020 9:28 AM by 小黄