laravel的IOC容器和php反射机制

:-}

以下是代码实例,利用反射可以寻找类的【构造函数中的参数】,然后根据【类型提示类】,利用反射机制实例化类,从而实现依赖加载

<?php
/**
*
* 工具类,使用该类来实现自动依赖注入。
*
*/
class Ioc {

    static $i = 0;

    // 获得类的对象实例
    public static function getInstance($className) {

        $paramArr = self::getMethodParams($className);
        var_dump($paramArr);die;
        return (new ReflectionClass($className))->newInstanceArgs($paramArr);//newInstanceArgs 从给出的参数创建一个新的类实例。
    }

    /**
     * 执行类的方法
     * @param  [type] $className  [类名]
     * @param  [type] $methodName [方法名称]
     * @param  [type] $params     [额外的参数]
     * @return [type]             [description]
     */
    public static function make($className, $methodName, $params = []) {

        // 获取类的实例
        $instance = self::getInstance($className);

        // 获取该方法所需要依赖注入的参数
        $paramArr = self::getMethodParams($className, $methodName);

        return $instance->{$methodName}(...array_merge($paramArr, $params));// ... 可变函数参数
    }

    /**
     * 获得类的方法参数,只获得有类型的参数
     * @param  [type] $className   [description]
     * @param  [type] $methodsName [description]
     * @return [type]              [description]
     */
    protected static function getMethodParams($className, $methodsName = '__construct') {
self::$i++;
        // 通过反射获得该类
        $class = new ReflectionClass($className);
        echo  "<pre>";
        // print_r($class);
        $paramArr = []; // 记录参数,和参数类型
        // dd($class);
  //       ReflectionClass Object
        // (
        //     [name] => B
        // )

        // 判断该类是否有构造函数
        if ($class->hasMethod($methodsName)) {
            // 获得构造函数
            $construct = $class->getMethod($methodsName); //getMethod 检查方法是否已定义
            // dd($construct);  
            //ReflectionMethod Object
            // (
            //     [name] => __construct
            //     [class] => B
            // )

            // 判断构造函数是否有参数
            $params = $construct->getParameters();// 获取参数
            // dd($params);
            //  Array
            // (
            //     [0] => ReflectionParameter Object
            //         (
            //             [name] => a
            //         )
            // )


            if (count($params) > 0) {

                // 判断参数类型
                foreach ($params as $key => $param) {

                    if ($paramClass = $param->getClass()) { //getClass 获得类型提示类
                        // dd($paramClass);
      //                   ReflectionClass Object
                        // (
                        //     [name] => A
                        // )

                        // 获得参数类型名称
                        $paramClassName = $paramClass->getName(); //获取类名
                        // dd($paramClassName);
                        // A

                        // 获得参数类型
                        $args = self::getMethodParams($paramClassName);
                        // print_r($args);
                        // Array
                        // (
                        // )
                        // Array
                        // (
                        //     [0] => C Object
                        //         (
                        //         )

                        // )


                        $paramArr[] = (new ReflectionClass($paramClass->getName()))->newInstanceArgs($args); 
                        // print_r($paramArr);
//                         Array
                        // (
                        //     [0] => C Object
                        //         (
                        //         )

                        // )
//                         Array
                        // (
                        //     [0] => A Object
                        //         (
                        //             [cObj:protected] => C Object
                        //                 (
                        //                 )
                        //         )
                        // )
                        //  newInstanceArgs 从给出的参数创建一个新的类实例。

                    }
                }
            }
        }

        return $paramArr;
    }
}


class A {

    protected $cObj;

    /**
     * 用于测试多级依赖注入 B依赖A,A依赖C
     * @param C $c [description]
     */
    public function __construct(C $c) {

        $this->cObj = $c;
    }

    public function aa() {

        echo 'this is A->test';
    }

    public function aac() {

        $this->cObj->cc();
    }
}

class B {

    protected $aObj;

    /**
     * 测试构造函数依赖注入
     * @param A $a [使用引来注入A]
     */
    public function __construct(A $a) {

        $this->aObj = $a;
    }

    /**
     * [测试方法调用依赖注入]
     * @param  C      $c [依赖注入C]
     * @param  string $b [这个是自己手动填写的参数]
     * @return [type]    [description]
     */
    public function bb(C $c, $b) {

        $c->cc();
        echo "\r\n";

        echo 'params:' . $b;
    }

    /**
     * 验证依赖注入是否成功
     * @return [type] [description]
     */
    public function bbb() {

        $this->aObj->aac();
    }
}

class C {

    public function cc() {

        echo 'this is C->cc';
    }
}

function dd($dd){
    echo "<pre>";
    print_r($dd);
    die;
}


//实例化B,B构造依赖A,A构造依赖C.

// 使用Ioc来创建B类的实例,B的构造函数依赖A类,A的构造函数依赖C类。
$bObj = Ioc::getInstance('B');
$bObj->bbb(); // 输出:this is C->cc , 说明依赖注入成功。

// 打印$bObj
// var_dump($bObj);

// // 打印结果,可以看出B中有A实例,A中有C实例,说明依赖注入成功。
// object(B)#3 (1) {
//   ["aObj":protected]=>
//   object(A)#7 (1) {
//     ["cObj":protected]=>
//     object(C)#10 (0) {
//     }
//   }
// }


Ioc::make('B', 'bb', ['this is param b']);

// // 输出结果,可以看出依赖注入成功。
// this is C->cc
// params:this is param b