光羽 Blog

记录精彩的程序人生

Programs must be written for people to read, and only incidentally for machines to execute.
程序必须是为了给人看而写,给机器去执行只是附带任务.
  menu
9 文章
1530 浏览
0 当前访客
ღゝ◡╹)ノ❤️

十年前老项目引入IOC依赖注入

前言

由于机缘巧合,我需要去修改一份最早2012年的源码,这里,没有psr-1、psr-4、没有composer、没有provider、啥都没有……也没有mvc,或者说是特殊的mvc,所以这次就先给它加上IOC依赖注入,用来实现service层注入controller层

说说这项目的构造

在项目运行开始 run 之后
首先获取了request参数中的ama代表action,m代表method,再通过路径拼接的方式,找到action,执行其中给的function
image.png

为了不破坏原项目的完整性、在最后一行调用方法这个部分进行IOC的DI依赖注入

开始

直接上代码,注释都在代码里



    protected static $_singleton = []; // 存放单例示例

 /**

     * 添加单例实例

     * @param $instance 实例

     */

    public static function singleton($instance)

    {

        if (!is_object($instance)) {

            throw new InvalidArgumentException('Object need');

        }

        $className = get_class($instance);

        // 不存在实例列表则加入

        if (!array_key_exists($className, self::$_singleton)) {

            self::$_singleton[$className] = $instance;

        }

    }

  

    /**

     * 获取一个实例

     * @param $className 类名

     */

    public static function getSingleton($className)

    {

        return array_key_exists($className, self::$_singleton) ?
    		 self::$_singleton[$className] : null;

    }

  

    /**

     * 销毁一个实例

     * @param $className 类名¬

     */

    public static function unsetSingleton($className)

    {

        self::$_singleton[$className] = null;

    }

  

    /**

     * 获取实例

     * @param 类名

     * @param array 参数

     * @return 实例

     */

    public static function getInstance($className, $params = [])

    {

        // 获取反射实例

        $reflector = new ReflectionClass($className);

        // 获取实例的构造方法

        $constructor = $reflector->getConstructor();

        // 用来存放可以注入的实例

        $tmpParams = [];

        foreach ($constructor->getParameters() as $param) {

            $class = $param->getClass();

            if ($class) {

                $singleton = self::getSingleton($class->name); // 直接获取实例

                // 是否有实例,没有的话就获取

                $tmpParams[] = $singleton ? $singleton : self::getInstance($class->name);

            }

        }

        $tmpParams = array_merge($tmpParams, $params);

        return $reflector->newInstanceArgs($tmpParams);

    }

测试action变量

image.png

同时随便写个接口测试一下

image.png

这里可以看到,action是没问题的
可是它已经把实例创建好了,这可如何是好……所以改源码吧
image.png
源码在这里……

新增一个运行方法的函数

 /**
     * 运行Action
     * @param $className 类名
     * @param $method 方法名
     * @param array 方法参数
     * @param array 构造方法参数
     */
    public static function runAction($className, $method, $params = [], $construct_params = [])
    {
        if (!class_exists($className)) {
            throw new BadMethodCallException("Class $className is not found!");
        }

        if (!method_exists($className, $method)) {
            throw new BadMethodCallException("undefined method $method in $className !");
        }

        $instance        = self::getInstance($className, $construct_params);
        $reflector       = new ReflectionClass($className);
        $reflectorMethod = $reflector->getMethod($method);
        $tmpParams       = [];
        foreach ($reflectorMethod->getParameters() as $param) {
            $class = $param->getClass();
            if ($class) {
                $singleton   = self::getSingleton($class->name);
                $tmpParams[] = $singleton ? $singleton : self::getInstance($class->name);
            }
        }
        return call_user_func_array([$instance, $method], array_merge($tmpParams, $params));
    }

这时候就只差获取类和方法名了
前面说到am分别代表action和method,method是不要处理了,但是a的话,要加上Action后缀,或许还要加上命名空间

image.png

……
少了个s
image.png

这样调用runAction之后,就会根据params中是否携带class来进行依赖注入

测试

image.png
在构造方法里面有个Goods参数
同时在test方法里面调用good的test函数

image.png

依赖注入成功!!!


标题:十年前老项目引入IOC依赖注入
作者:lty5240
地址:http://blog.lintyone.cn/articles/2019/10/13/1570943882084.html
Programs must be written for people to read, and only incidentally for machines to execute.
程序必须是为了给人看而写,给机器去执行只是附带任务.