面向?qū)ο蟮母呒?jí)語(yǔ)言都應(yīng)該提供了反射機(jī)制,可以動(dòng)態(tài)的獲取類的信息,否則語(yǔ)言就缺少靈活性,很多需求無(wú)法完成,php的反射相當(dāng)于iOS里面的運(yùn)行時(shí)方法。iOS的運(yùn)行系統(tǒng)提供了一系列的C語(yǔ)言方法動(dòng)態(tài)的獲取類的信息,處理消息轉(zhuǎn)發(fā),php也提供了類似的實(shí)現(xiàn),相比iOS使用更簡(jiǎn)便,下面是幾個(gè)案例。
- 獲取函數(shù)的信息
<?php
/**
* Created by PhpStorm.
* User: wangguodong
* Date: 17/3/2
* Time: 下午10:44
*/
/**
* 這是testfun的注釋
*/
function testfun($name = 'test'){
echo "this is a $name method";
return 'a';
}
testfun();
//通過(guò)一個(gè)函數(shù)名初始化一個(gè)函數(shù)反射對(duì)象,取獲取函數(shù)的相關(guān)信息
$ref_fun = new ReflectionFunction('testfun');
//函數(shù)的所在的文件
echo '<br>函數(shù)的文件位置是:'.$ref_fun->getFileName();
//獲取函數(shù)的開(kāi)始行編號(hào)
echo '<br>函數(shù)的起始位置是:'.$ref_fun->getStartLine();
//獲取函數(shù)末尾的編號(hào)
echo '<br>函數(shù)的結(jié)束位置是:'.$ref_fun->getEndLine();
//函數(shù)的注釋
echo '<br>函數(shù)的注釋是:'.$ref_fun->getDocComment();
//獲取參數(shù)的個(gè)數(shù)
echo '<br>函數(shù)的參數(shù)個(gè)數(shù)是:'.$ref_fun->getNumberOfParameters();
//獲取具體的參數(shù)信息
echo '<br>函數(shù)的參數(shù)是:';print_r($ref_fun->getParameters());
//函數(shù)的返回值 --這里提示這個(gè)方法不存在
echo '<br>函數(shù)的返回值是:'.$ref_fun->getReturnType();
//如果反射一個(gè)不存在的函數(shù),會(huì)拋出一個(gè)異常,應(yīng)該try catch 使用
try{
$ref_nfun = new ReflectionFunction('no_exist');
}catch (ReflectionException $e){
echo $e->getMessage();
}
2.類的信息
class Person{
public $name,$age,$sex;
static function show($name,$age,$sex='男'){
echo "姓名:$name,年齡:$age,性別:$sex";
}
function say($content){
echo "我想說(shuō)的是:$content";
}
function eat($food= 'apple'){
}
}
$per = new Person();
$ref = new ReflectionClass('Person');//參數(shù)可以是類名,或者類的實(shí)例
//獲取類里面的所有方法
$class_methods = $ref->getMethods();
//是一個(gè)數(shù)組,每個(gè)對(duì)象包含了方法名和所屬類
echo '<br/>';
echo "<pre>";print_r($class_methods);echo "<pre>";
//是否擁有某個(gè)方法
$has_method = $ref->hasMethod('say');
//獲取某個(gè)方法的信息
$some_method = new ReflectionMethod('Person','say');
$some_method->isPrivate();//判斷是否私有,還有static,public
//方法的調(diào)用,
if ($some_method->isPublic()&&!$some_method->isAbstract()) {
if ($some_method->isStatic()){
//靜態(tài)方法第一個(gè)參數(shù)是null,后面參數(shù)寫(xiě)方法的參數(shù),可以傳遞一個(gè)或者多個(gè),并且這個(gè)方法可以接受數(shù)量可變的參數(shù)。
/*
* * The object to invoke the method on. For static methods, pass
* null to this parameter.
* </p>
* @param mixed $parameter [optional] <p>
* Zero or more parameters to be passed to the method.
* It accepts a variable number of parameters which are passed to the method.
* </p>
*/
$some_method->invoke(null,'zhangsan','23');
}
else {
//非靜態(tài)方法第一個(gè)參數(shù)傳遞一個(gè)對(duì)象
$some_method->invoke($per,'生活真好');
}
}
}
- 動(dòng)態(tài)代理
消息的轉(zhuǎn)發(fā),交給其他類處理,iOS可以通過(guò)delegate實(shí)現(xiàn),也可以在運(yùn)行時(shí)通過(guò)相應(yīng)的方法轉(zhuǎn)發(fā)。
//調(diào)用B的show方法時(shí)候去調(diào)用A的show方法
class A{
function show(){
echo "classA的show方法";
}
}
class B{
private $obj;
function __construct(){
$this->obj = new A();
}
function __call($name, $arguments)
{
$ref = new ReflectionClass($this->obj);
if ($ref->hasMethod($name)){
$method = $ref->getMethod($name);
if ($method->isPublic()&&!$method->isAbstract()&&count($arguments)){
if ($method->isStatic()){
$method->invoke(null);
}
else{
$method->invoke($this->obj);
}
}
}
}
}
- 插件案例
include_once __DIR__."/plugin.php";
function get_plugin_menus(){
$menus = array();
$all_class = get_declared_classes();//獲取所有的類
foreach ($all_class as $cls){
$ref_cls = new ReflectionClass($cls);
if ($ref_cls->implementsInterface('Plugin')){//是否實(shí)現(xiàn)了某個(gè)接口
if ($ref_cls->hasMethod('showMenu')){
$method = $ref_cls->getMethod("showMenu");
if ($method->isStatic()){
$method->invoke(null);
}
else{
// $method->invoke(new $cls());//這樣獲取類
$instance = $ref_cls->newInstance();
$menu = $method->invoke($instance);
}
}
}
$menus = array_merge($menus,$menu);
}
return $menus;
}
echo "<pre>";get_plugin_menus();echo "<pre>";
interface Plugin{
function showMenu();
}
class MyPlugin implements Plugin{
function showMenu()
{
$menu = array(
array(
'name' => 'menu1', 'link' => 'index.php?act=link1'
),
array(
'name' => 'menu2', 'link' => 'index.php?act=link2'
)
);
return $menu;
}