Skip to main content

浅析PHP之反射

一、反射是啥

反射,顾名思义,反着射过去,开个玩笑,官网是这么说的,如下。

PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。

大概可以这么理解,反射其实就是获取类、函数的属性、方法、控制权限信息,用来控制类方法,实现过滤或依赖注入。

PHP反射api由若干类组成,可帮助我们用来访问程序的元数据或者同相关的注释交互。

借助反射我们可以获取诸如类实现了那些方法,创建一个类的实例(不同于用new创建),调用一个方法(也不同于常规调用),传递参数,动态调用类的静态方法。

二、反射应用场景

  • 类方法的过滤器
  • 实现依赖注入
  • 自动加载插件、文档

三、反射相关函数

列举几个常用的API:

1.Reflection

2.ReflectionClass — ReflectionClass 类

3.ReflectionMethod — ReflectionMethod 类

 

四、反射使用

1.打印类信息和修饰符名称

<?php
class Son{
	private function eat(){
		echo "eating";
	}
	public function sleep(){
		echo "sleep";
	}
}
//打印所有信息
var_dump(Reflection::export(new ReflectionClass('Son')));
//打印访问控制符
$foo = new ReflectionMethod('Son', 'eat');
echo "Modifiers for method eat():\n";
echo $foo->getModifiers() . "\n";    //返回一个方法的修饰符,返回值是一个位标
echo implode(' ', Reflection::getModifierNames($foo->getModifiers())) . "\n";

返回:

Class [  class Son ] {
  @@ /home/www/backworld/index.php 2-9

  - Constants [0] {
  }

  - Static properties [0] {
  }

  - Static methods [0] {
  }

  - Properties [0] {
  }

  - Methods [2] {
    Method [  private method eat ] {
      @@ /home/www/backworld/index.php 3 - 5
    }

    Method [  public method sleep ] {
      @@ /home/www/backworld/index.php 6 - 8
    }
  }
}

NULL
Modifiers for method eat():
134284288
private

2.获取类属性和方法

<?php
class Son{
	public  $name = 'Hello';
	private $age = 123;
	private function eat(){
		echo "eating";
	}
	public function sleep(){
		echo "sleep";
	}
}
echo '<pre>';
//获取属性
$class = new ReflectionClass('Son');
//获取所有方法,可以按照如下过滤
/*
ReflectionMethod::IS_STATIC
ReflectionMethod::IS_PUBLIC
ReflectionMethod::IS_PROTECTED
ReflectionMethod::IS_PRIVATE 
ReflectionMethod::IS_ABSTRACT
ReflectionMethod::IS_FINAL 
*/
print_r($class->getMethods(ReflectionMethod::IS_PUBLIC));
print_r($class->getMethods());//获取所有方法
print_r($class->getProperties());//获取所有属性
foreach ($class->getMethods() as $key => $value) {
	echo $value->name;
}
foreach ($class->getProperties() as $key => $value) {
	echo $value->name;
}
echo '</pre>';die;

返回结果:

Array
(
    [0] => ReflectionMethod Object
        (
            [name] => sleep
            [class] => Son
        )

)
Array
(
    [0] => ReflectionMethod Object
        (
            [name] => eat
            [class] => Son
        )

    [1] => ReflectionMethod Object
        (
            [name] => sleep
            [class] => Son
        )

)
Array
(
    [0] => ReflectionProperty Object
        (
            [name] => name
            [class] => Son
        )

    [1] => ReflectionProperty Object
        (
            [name] => age
            [class] => Son
        )

)
eatsleepnameage

3.使用反射充当代理,做调用filter

<?php
class mysql
{
    public function connect($db)
    {
        echo "连接到数据库{$db[0]}".PHP_EOL;
    }
}

class sqlproxy
{
    private $target;
    public function __construct($tar)
    {
        $this->target[] = new $tar;
    }
    public function __call($name,$args)
    {
        foreach($this->target as $obj)
        {
            $r = new ReflectionClass($obj);
            if($method = $r->getMethod($name))
            {
                if($method->isPublic() && !$method->isAbstract())
                {
                    echo "方法前拦截记录LOG".PHP_EOL;
                    $method->invoke($obj,$args);
                    echo "方法后拦截".PHP_EOL;
                }
            }
        }
    }
}
$obj = new sqlproxy('mysql');
echo $obj->connect('Succ');

返回结果:

方法前拦截记录LOG 连接到数据库Succ 方法后拦截

4.使用反射调用对象私有方法

<?php
class Myclass{
    private function myFun(){
        echo "my is private";
    }
}
//通过类名MyClass进行反射
$ref_class = new ReflectionClass('MyClass');
//通过反射类进行实例化
$instance  = $ref_class->newInstance();
//通过方法名myFun获取指定方法
$method = $ref_class->getmethod('myFun');
//设置可访问性
$method->setAccessible(true);
//执行方法
$method->invoke($instance);

 

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

+ 61 = 63