在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對象,比如參數標註了傳哪個類的實例,這個方法就可以獲取到對應的反射類對象。
//所以我們要注入對象的時候,參數要標註完整的類名。
上面三個反射類對應了一個實例的類,方法,方法的參數。實現依賴注入的時候,就是通過反射,找到一個類所要依賴哪些類。