服务容器Ioc的示例分析

发布时间:2021-12-27 10:52:46 作者:小新
来源:亿速云 阅读:176

小编给大家分享一下服务容器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());

以上是“服务容器Ioc的示例分析”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. Spring IOC 容器源码分析
  2. Spring ioc容器介绍

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

ioc

上一篇:2021年值得学习的web编程语言有哪些

下一篇:receiver based Dstream怎么用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》