美文网首页PHP
(四)从零编写PHP容器-添加绑定解析

(四)从零编写PHP容器-添加绑定解析

作者: FinalZero | 来源:发表于2020-02-19 16:48 被阅读0次

    项目源码

    功能实现

    1. 代码优化
    2. 添加绑定解析,优先从绑定实例中获取参数实例

    代码实现 Container

    use Closure;
    use Exception;
    use Psr\Container\ContainerExceptionInterface;
    use ReflectionClass;
    use ReflectionException;
    use ReflectionParameter;
    
    class Container
    {
        /**
         * @var array
         */
        protected $binds = [];
    
        /**
         * @param string $abstract
         * @param mixed $instance
         * @return $this
         */
        public function bind(string $abstract, $instance)
        {
            $this->binds[$abstract] = $instance;
            return $this;
        }
        
        /**
         * create a new object
         * @param string $abstract
         * @return Closure|object
         * @throws ReflectionException
         * @throws Exception
         */
        public function create($abstract)
        {
            return $this->createInstance($abstract);
        }
        
        /**
         * create new instance
         * @param string $abstract
         * @param array $tmp
         * @return Closure|object
         * @throws ReflectionException
         * @throws Exception
         */
        protected function createInstance(string $abstract, array $tmp = [])
        {
            if (isset($this->binds[$abstract])) {
                return $this->binds[$abstract];
            } else if (isset($tmp[$abstract])) {
                return $tmp[$abstract];
            } else if (array_key_exists($abstract, $tmp)) {
                throw new class('can not create a circular dependencies class object.') extends Exception implements ContainerExceptionInterface{ };
            } else {
                $tmp[$abstract] = null;
            }
            $refClass = new ReflectionClass($abstract);
            if ($refClass->isInterface() || $refClass->isAbstract()) {
                throw new class('can not create a class in interface or abstract.') extends Exception implements ContainerExceptionInterface{ };
            } elseif ($refClass->getName() === Closure::class) {
                return function () {};
            } elseif ($refClass->hasMethod('__construct')) {
                $_constructParams = array_map(function (ReflectionParameter $param) use ($abstract, $tmp) {
                    if ($result = $this->paramsHandle($param) instanceof ReflectionClass) {
                        return $this->createInstance($param->getClass()->getName(), $tmp);
                    } else {
                        return $result;
                    }
                }, $refClass->getMethod('__construct')->getParameters());
            }
            return $tmp[$abstract] = $refClass->newInstance(... ($_constructParams ?? []));
        }
        
        /**
         * @param ReflectionParameter $param
         * @return mixed|ReflectionClass|null
         * @throws ReflectionException
         */
        private function paramsHandle(ReflectionParameter $param)
        {
            if ($param->getClass()) {
                return $param->getClass();
            } elseif ($param->isDefaultValueAvailable()) {
                return $param->getDefaultValue();
            } elseif ($param->getType()) {
                return [
                        'string' => '',
                        'int' => 0,
                        'array' => [],
                        'bool' => false,
                        'float' => 0.0,
                        'iterable' => [],
                        'callable' => function() {}
                    ][$param->getType()->getName()] ?? null;
            } else {
                return null;
            }
        }
    }
    
    • 注: AbsSingleton为实现单例的抽象类,包含一个getInstance()静态方法,可忽略

    实现思路

    实现思路

    1. 将基础数据类型判断先做分离(方便后期会做基础数据的动态映射)
    2. 在容器类中添加一个binds存储绑定的类
    3. 在创建方法createInstance中读取变量

    示例

    class E
    {
        protected $msg;
    
        public function __construct($msg)
        {
            $this->msg = $msg;
        }
    
        public function show()
        {
            return $this->msg;
        }
    }
    
    class D
    {
        protected $e;
    
        public function __construct(E $e)
        {
            $this->e = $e;
        }
    
        public function show()
        {
            $this->e->show();
        }
    }
    
    $container = new Container();
    
    $container->bind(E::class, new E('123'));
    
    # 将获取到绑定的`new E('123')`的实例
    $e = $container->create(E::class)
    $e->show(); // 123
    
    $d = $container->create(D::class)
    $d->show(); // 123
    

    相关文章

      网友评论

        本文标题:(四)从零编写PHP容器-添加绑定解析

        本文链接:https://www.haomeiwen.com/subject/bxwafhtx.html