php 反射機制案例

給我一瓶冰闊洛發表於2020-12-12
<?php
class Ioc {

    // 獲得類的物件例項
    public static function getInstance($className) {

        $paramArr = self::getMethodParams($className);

        return (new ReflectionClass($className))->newInstanceArgs($paramArr);
    }

    /**
     * 執行類的方法
     * @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') {

        // 通過反射獲得該類
        $class = new ReflectionClass($className);
        $paramArr = []; // 記錄引數,和引數型別

        // 判斷該類是否有建構函式
        if ($class->hasMethod($methodsName)) {

            // 獲得建構函式
            $construct = $class->getMethod($methodsName);

            // 判斷建構函式是否有引數
            $params = $construct->getParameters();
            if (count($params) > 0) {
                // 判斷引數型別
                foreach ($params as $key => $param) {
                    //getClass 獲取引數的型別提示類
                    // __construct(A,$a)    getClass 獲取的是A  型別為ReflectionClass物件。
                    if ($paramClass = $param->getClass()) {
                        $paramClassName = $paramClass->getName();
                        // 獲得引數型別
                        $args = self::getMethodParams($paramClassName);
                        $paramArr[] = (new ReflectionClass($paramClass->getName()))->newInstanceArgs($args);
                        
                    }
                }
            }
        }

        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';
    }
}

// 使用Ioc來建立B類的例項,B的建構函式依賴A類,A的建構函式依賴C類。
$bObj = Ioc::getInstance('B');
$bObj->bbb(); // 輸出:this is C->cc , 說明依賴注入成功。
//
 列印$bObj
var_dump($bObj);







?>

 

相關文章