Reflection反射机制
php5添加了一项新的功能:Reflection
。这个功能使得程序员可以reflection class,interface,function,method …..。通过PHP代码,就可以得到某类/方法等的所有信息,并且可以和它交互。
反射类 | 可得到的信息 | |
---|---|---|
ReflectionFunction() | 函数定义所在的文件以及起始位置等。 | |
ReflectionClass() | 常量/属性/方法/命名空间/类是否为flnal或者abstract等。 | |
ReflectionMethod() | 方法修饰类型/方法名/方法注释等。 |
使用方法
ReflectionFunction
<?php
/**
* 测试函数
* @author 启东
*/
function test(){
echo "我是一个测试函数<br/>";
}
test();
$ref_fun = new ReflectionFunction('test');//反射函数类
echo $ref_fun->getDocComment(),"<br/>";//函数注释 如果new的是类 使用时类注释
//如果是方法 就是获取方法注释
echo "定义的所在文件名:",$ref_fun->getFileName(),"<br/>";//函数定义文件
echo "代码开始行".$ref_fun->getStartLine()."<br/>";//开始行
echo "代码结束行".$ref_fun->getEndLine()."<br/>";//结束行
try {
new ReflectionFunction("test1");
}catch(ReflectionException $e){
echo $e->getMessage(),"<br/>";
};
ReflectionClass
<?php
class A{
function t1(){
echo "我是一个不带参数的方法<br/>";
}
function t2($str){
echo "我是一个带一个参数的方法t2,参数是:",$str,"<br/>";
}
private function t3(){
}
static function t4(){
echo "我是一个静态方法<br/>";
}
}
$a=new A();
$ref_cls= new ReflectionClass('A');//参数可以是类名,也可以是类的一个实例
//获取类中的所有方法
$class_all_method=$ref_cls->getMethods();//获取这个类的所有方法
var_dump($class_all_method);
/**
F:\Work\test\test.php:21:
array (size=4)
0 =>
object(ReflectionMethod)[3]
public 'name' => string 't1' (length=2)
public 'class' => string 'A' (length=1)
1 =>
object(ReflectionMethod)[4]
public 'name' => string 't2' (length=2)
public 'class' => string 'A' (length=1)
2 =>
object(ReflectionMethod)[5]
public 'name' => string 't3' (length=2)
public 'class' => string 'A' (length=1)
3 =>
object(ReflectionMethod)[6]
public 'name' => string 't4' (length=2)
public 'class' => string 'A' (length=1)
*/
//判断类中是否有某个方法 hasMethod 返回布尔值
var_dump($ref_cls->hasMethod('t1')); //true
var_dump($ref_cls->hasMethod('tt'));//false
//判断方法的修饰符 public protected private static
//判断方式:is+修饰符 返回布尔值。
//判断之前获取类中的方法
$ref_method=$ref_cls->getMethod('t1');
var_dump($ref_method->isPublic());//判断是否是公开方法
ReflectionMethod
<?php
class A{
function t1(){
echo "我是一个不带参数的方法<br/>";
}
function t2($str){
echo "我是一个带一个参数的方法t2,参数是:",$str,"<br/>";
}
private function t3(){
}
static function t4(){
echo "我是一个静态方法<br/>";
}
}
$a=new A();
$ref_cls= new ReflectionClass('A');//参数可以是类名,也可以是类的一个实例
//获取类中的方法的反射类
$ref_method=new ReflectionMethod($a,'t3');
var_dump($ref_method->isPublic());//是否公开方法
$ref_method=new ReflectionMethod('A','t4');
var_dump($ref_method->isStatic());//是否静态方法
//获取方法 然后执行方法
$ref_method=$ref_cls->getMethod('t1');
//静态方法调用 invoke(null,参数)
//普通方法调用 invoke(实例对象,参数)
//私有或受保护的方法不能被invoke调用
if($ref_method->isPublic() && !$ref_method->isAbstract()){
if($ref_method->isStatic()){
$ref_method->invoke(null);
}else{
$ref_method->invoke($a);
}
}
//静态方法invoke调用
$ref_method=$ref_cls->getMethod('t4');
if($ref_method->isPublic() && !$ref_method->isAbstract()){
if($ref_method->isStatic()){
$ref_method->invoke(null);
}else{
$ref_method->invoke($a);
}
}
//带参数的invoke调用
$ref_method=$ref_cls->getMethod('t2');
if($ref_method->isPublic() && !$ref_method->isAbstract()){
if($ref_method->isStatic()){
$ref_method->invoke(null);
}else{
$ref_method->invoke($a,'什么');
}
}
动态代理
动态代理:也叫委托模式,在委托模式中,有两个对象参与处理同意个请求,接受请求的对象将请求委托给另一个对象来处理。
代码示例:
<?php
class A{
function showInfo(){
echo "Class A showInfo<br/>";
}
}
class B{
private $obj;
function __construct(){
$this->obj = new A();
}
function addObj($obj){
$this->obj[]=$obj;
}
function __call($name,$args){
$ref_cls= new ReflectionClass($this->obj);
if($ref_cls->hasMethod($name)){
$ref_method=$ref_cls->getMethod($name);
if($ref_method->isPublic() && !$ref_method->isAbstract()){
if($ref_method->isStatic()){
$ref_method->invoke(null);
}else{
$ref_method->invoke($this->obj);
}
}
}
}
}
$b= new B();
$b->showInfo();
<?php
class A{
function showInfo(){
echo "Class A showInfo<br/>";
}
}
class B{
private $obj;
function __construct(){
$this->obj = new A();
}
function addObj($obj){
$this->obj[]=$obj;
}
function __call($name,$args){
$ref_cls= new ReflectionClass($this->obj);
if($ref_cls->hasMethod($name)){
$ref_method=$ref_cls->getMethod($name);
if($ref_method->isPublic() && !$ref_method->isAbstract()){
if($ref_method->isStatic()){
$ref_method->invoke(null);
}else{
$ref_method->invoke($this->obj);
}
}
}
}
}
$b= new B();
$b->showInfo();
插件系统:利用反射机制自动获取插件列表以及其他的相关信息。
定义test.php文件代码示例如下
<?php
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;
}
}
class YourPlugin implements Plugin{
//获取插件菜单
function showMenu()
{
$menu=array(
array(
'name'=>'menu3',
'link'=>'index.php?act=your_link3'
),
array(
'name'=>'menu4',
'link'=>'index.php?act=your_link4'
)
);
return $menu;
}
}
定义代码示例a.php 并运行a.php
<?php
include_once __DIR__.'/test.php';
/**
* 获取插件的菜单
*/
function get_plugin_menus(){
$all_class=get_declared_classes();
$menus=$menu=[];
foreach ($all_class as $cls){
$ref_cls= new ReflectionClass($cls);
//判断这个类是否实现某个接口
if($ref_cls->implementsInterface('plugin')){
if($ref_cls->hasMethod('showMenu')){
$ref_method=$ref_cls->getMethod('showMenu');
if($ref_method->isPublic() && !$ref_method->isAbstract()) {
if ($ref_method->isStatic()) {
$menu=$ref_method->invoke(null);
} else {
//通过反射类获取类的一个实例
$instance=$ref_cls->newInstance();
$menu=$ref_method->invoke($instance);
//$ref_method->invoke(new $cls);
}
}
}
}
$menus=array_merge($menus,$menu);
}
return $menus;
}
$menu_list=get_plugin_menus();
var_dump($menu_list);