zoukankan      html  css  js  c++  java
  • 模拟服务容器Ioc

    服务容器是一个用于管理类依赖和执行依赖注入的强大工具。

     一个类要被容器所能够提取,必须要先注册至这个容器。既然称这个容器叫做服务容器,那么我们需要某个服务,就得先注册、绑定这个服务到容器,那么提供服务并绑定服务至容器的东西就是服务提供器(ServiceProvider)。

    依赖注入和控制反转是对同一件事情的不同描述,它们描述的角度不同。依赖注入是从应用程序的角度在描述,应用程序依赖容器创建并注入它所需要的外部资源。而控制反转是从容器的角度在描述,容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

    <?php
    
    /**
     * Interface Log
     * 面向接口编程
     */
    interface Log
    {
        public function write();
    }
    
    class FileLog implements Log
    {
        public function write()
        {
            echo 'filelog write...' . PHP_EOL;
        }
    }
    
    class DataBaseLog implements Log
    {
        public function write()
        {
            echo 'dblog write...' . PHP_EOL;
        }
    }
    
    /**
     * Class Request
     * 模拟请求类
     */
    class Request
    {
        public function toArray()
        {
            return ['name' => 'value'];
        }
    }
    
    /**
     * User类依赖Log接口的实现
     */
    class User
    {
        private $log;
        private $extra;
    
        public function __construct(Log $log, $a, $b, $c = '默认参数')
        {
            $this->log = $log;
            $this->extra = compact('a', 'b', 'c');
        }
    
        /**
         * 模拟用户登录写入登录日志
         */
        public function login(Request $request)
        {
            echo '接收登录请求的参数json:' . json_encode($request->toArray()) . PHP_EOL;
            echo 'user log success...' . PHP_EOL;
            $this->log->write();
        }
    
        public function getExtra()
        {
            var_dump($this->extra);
        }
    }
    
    
    /**
     * Class Ioc
     * 模拟IoC容器
     * 类从注册到实例化,最终被我们所使用,都是服务容器负责
     */
    class Ioc
    {
        protected $bindings = [];
        protected $instances = [];
        protected static $ioc;
    
        protected function __construct()
        {
        }
    
        public static function getInstance()
        {
            if (is_null(self::$ioc)) {
                self::$ioc = new self();
            }
            return self::$ioc;
        }
    
        /**
         * 注册绑定 (绑定自身、闭包、接口)
         * 也就是服务
         * @param $abstract
         * @param null $concrete
         * @param bool $share
         */
        public function bind($abstract, $concrete = null, $share = true)
        {
            if (is_null($concrete)) {
                $concrete = $abstract;
            }
            $this->bindings[$abstract]['share'] = $share;
            if ($concrete instanceof Closure) {
                $this->bindings[$abstract]['concrete'] = $concrete;
            } else {
                $this->bindings[$abstract]['concrete'] = function (Ioc $ioc, $vars = []) use ($concrete) {
                    return $ioc->build($concrete, $vars);
                };
            }
        }
    
        /**
         * 返回对象
         * @param $abstract
         * @param array $vars
         * @return mixed
         * @throws ReflectionException
         */
        public function make($abstract, $vars = [])
        {
            if (isset($this->instances[$abstract])) {
                return $this->instances[$abstract];
            }
    
            if (isset($this->bindings[$abstract]['concrete'])) {
                $concrete = $this->bindings[$abstract]['concrete'];
                $instance = $concrete($this, $vars);
                if ($this->bindings[$abstract]['share']) {
                    $this->instances[$abstract] = $instance;
                }
                return $instance;
            }
    
            throw new RuntimeException($abstract . ' is not bound yet');
        }
    
        /**
         * 创建对象
         * @param $concrete
         * @return object
         * @throws ReflectionException
         */
        public function build($concrete, $vars = [])
        {
            $reflectionClass = new ReflectionClass($concrete);
            $constructor = $reflectionClass->getConstructor();
            if (is_null($constructor)) {
                return $reflectionClass->newInstance();
            }
            $isInstantiable = $reflectionClass->isInstantiable();
            if (!$isInstantiable) {
                throw new ReflectionException("{$concrete} cant construct");
            }
            $parameters = $constructor->getParameters();
            $dependencies = $this->getDependencies($parameters, $vars);
            return $reflectionClass->newInstanceArgs($dependencies);
        }
    
        /**
         * 获取参数的依赖
         * @param array $parameters
         * @return array
         * @throws ReflectionException
         */
        public function getDependencies(array $parameters, $vars = [])
        {
            $dependencies = [];
            reset($vars);
            $type = key($vars) === 0 ? 'figure' : 'letter';
            /**
             * @var ReflectionParameter $parameter
             */
            foreach ($parameters as $parameter) {
                $dependency = $parameter->getClass();
                $name = $parameter->getName();
                if ($dependency) {
                    $dependencies[] = $this->getObjectParam($dependency->getName(), $vars);
                } elseif ('figure' == $type && !empty($vars)) {
                    $dependencies[] = array_shift($vars);
                } elseif ('letter' == $type && isset($vars[$name])) {
                    $dependencies[] = $vars[$name];
                } elseif ($parameter->isDefaultValueAvailable()) {
                    $dependencies[] = $parameter->getDefaultValue();
                } else {
                    throw new ReflectionException('The constructor of the ' . $parameter->getDeclaringClass()->getName() . ' class has no default value of $' . $name);
                }
            }
    
            return $dependencies;
        }
    
        /**
         * 获取对象类型的参数值
         * @access protected
         * @param string $className 类名
         * @param array $vars 参数
         * @return mixed
         */
        protected function getObjectParam($className, &$vars)
        {
            $array = $vars;
            $value = array_shift($array);
            if ($value instanceof $className) {
                $result = $value;
                array_shift($vars);
            } else {
                $result = $this->make($className);
            }
    
            return $result;
        }
    
        /**
         * @param null $key
         * @return array|mixed|null
         */
        public function getInstances($key = null)
        {
            if (is_null($key)) {
                return $this->instances;
            } elseif (isset($this->instances[$key])) {
                return $this->instances[$key];
            } else {
                return null;
            }
        }
    }
    
    
    // run
    /*
     | 模拟容器绑定
     */
    $ioc = Ioc::getInstance();
    $ioc->bind(Request::class);//绑定类
    $ioc->bind(Log::class, FileLog::class);//绑定接口
    //$ioc->bind(Log::class, DataBaseLog::class);
    $ioc->bind('test', function () {//绑定闭包
        return 'test' . PHP_EOL;
    });
    
    /*
     | 模拟路由访问 User 控制器下的 login 方法
     */
    $ioc->bind(User::class, null, true);
    $method = 'login';
    $reflectionMethod = new ReflectionMethod(User::class, $method);
    $parameters = $reflectionMethod->getParameters();
    $dependencies = $ioc->getDependencies($parameters);
    $user = $ioc->make(User::class, ['参数1', '参数2']);
    call_user_func_array([$user, $method], $dependencies);
    // 查看参数
    $user->getExtra();
    var_dump($ioc->getInstances());
  • 相关阅读:
    [leetcode]34.Find First and Last Position of Element in Sorted Array找区间
    [leetcode]278. First Bad Version首个坏版本
    [leetcode]367. Valid Perfect Square验证完全平方数
    [leetcode]45. Jump Game II青蛙跳(跳到终点最小步数)
    [leetcode]55. Jump Game青蛙跳(能否跳到终点)
    [leetcode]26. Remove Duplicates from Sorted Array有序数组去重(单个元素只出现一次)
    [leetcode]27. Remove Element删除元素
    [leetcode]20. Valid Parentheses有效括号序列
    [leetcode]15. 3Sum三数之和
    C#中的局部类型
  • 原文地址:https://www.cnblogs.com/cshaptx4869/p/11671003.html
Copyright © 2011-2022 走看看