php的反射機制

在PHP中,反射是指在PHP運行狀態中,擴展分析PHP程序,導出或者提取出關於類、屬性、方法、參數等的詳細信息,包括註釋。這種動態獲取信息以及動態調用對象方法的功能,被稱爲反射API。

其實就是通過一個對象,獲取到實例化這個對象的類的所有信息。包括所有屬性(共有,私有,靜態),所有方法(構造函數,私有函數),還有對應方法的參數信息,還有方法的註釋信息等等。

1.反射類對象ReflectionClass

$reflect = new ReflectionClass($class);//$class既可以是類名字符串,也可以是對象。得到一個反射類對象。

$reflect->hasMethod('__make'); //判斷類是否有__make方法

$constructor = $reflect->getConstructor();//獲取類的構造函數,返回的是ReflectionMethod對象

$obj = $reflect->newInstanceArgs($args);//實例化類,$args是給構造函數的。
//比如最上面的$class如果是一個類名字符串,這個方法相當於 new $class($args);

$reflect->getName();//返回完整的類名

2. ReflectionMethod類,繼承ReflectionFunctionAbstract

2.1如何獲得ReflectionMethod的實例

$reflect = new ReflectionClass($class);//$class既可以是類名字符串,也可以是對象。得到一個反射類對象。

//1.獲取特定的方法的ReflectionMethod實例
$reflect->getMethod('say'); //say方法的ReflectionMethod實例
$reflect->getConstructor();//獲取類的構造函數的ReflectionMethod實例

//2.獲取類所有方法的ReflectionMethod實例
$reflect->getMethods(); //返回一個數組,元素就是類所有方法的ReflectionMethod實例

//3.直接傳入$class和方法名獲得
new ReflectionMethod($class, 'say'); //say方法的ReflectionMethod實例

2.2 ReflectionMethod類的主要功能

$methodObj = new \ReflectionMethod($class, 'say'); //say方法的ReflectionMethod實例

$methodObj->isPublic(); //返回boole值
$methodObj->invokeArgs($class, $arg);//執行say方法,第一參數是調用方法的對象,如果是靜態對象,
//設置爲 null,第二個參數是傳給類方法的參數。
$methodObj->invoke($class);//和上面一樣,如果執行的方法是靜態類,那麼這個參數傳送 null。
$methodObj->getNumberOfParameters()//獲取say方法的參數個數,返回int
$methodObj->getParameters()//獲取say方法的參數,返回數組,元素是ReflectionParameter類的實例

這個$methodObj->invokeArgs($class,$arg);執行這個方法,其中$arg就是這個方法的參數,$arg是一個數組,順序和方法的形參順序一致。所以執行這個方法之前,我們還要先得到這個$arg數組。比如tp5.1框架就封裝了bindParams來獲取這個數組

 /**
     * 綁定參數
     * @access protected
     * @param  $reflect 就是要執行的那個方法的ReflectionMethod
     * @param  array     $vars    參數
     * @return array
     */
    protected function bindParams($reflect, $vars = [])
    {
        //方法沒有參數,返回空數組
        if ($reflect->getNumberOfParameters() == 0) {
            return [];
        }
        //得到所有參數的
        $params = $reflect->getParameters();
        foreach ($params as $param) {
            $name      = $param->getName();
            $lowerName = Loader::parseName($name);
            $class     = $param->getClass();//如果這個參數是某個類實例,返回類名

            if ($class) {
                $args[] = $this->getObjectParam($class->getName(), $vars);
            } elseif (1 == $type && !empty($vars)) {
                $args[] = array_shift($vars);
            } elseif (0 == $type && isset($vars[$name])) {
                $args[] = $vars[$name];
            } elseif (0 == $type && isset($vars[$lowerName])) {
                $args[] = $vars[$lowerName];
            } elseif ($param->isDefaultValueAvailable()) {
                $args[] = $param->getDefaultValue();
            } else {
                throw new InvalidArgumentException('method param miss:' . $name);
            }
        }
        return $args;
    }

3.ReflectionParameter 類

$methodObj = new \ReflectionMethod($class, 'say'); //say方法的ReflectionMethod實例
$params = $methodObj->getParameters();//得到數組,元素是ReflectionParameter實例
$paramObj = $params[0];

ReflectionParameter實例的作用
$paramObj->getName();//參數名
$paramObj->getClass();//返回ReflectionClass對象,比如參數標註了傳哪個類的實例,這個方法就可以獲取到對應的反射類對象。
//所以我們要注入對象的時候,參數要標註完整的類名。

上面三個反射類對應了一個實例的類,方法,方法的參數。實現依賴注入的時候,就是通過反射,找到一個類所要依賴哪些類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章