1. 文章
  2. 文章详情

PHP反射API的使用

像是依赖注入,对象池,类加载,一些设计模式等等,都用到了反射机制。

首先,构建一个简单的类:

/*属性接口*/
interface Property
{
    function work();
}

class Person
{
    public $name;
    public function __construct($name)
    {
        $this->name = $name;
    }
}

class StudentController implements Property
{
    //set方法,但需要Person对象参数
    public function setPerson(Person $obj_person)
    {
        echo 'Student ' . $obj_person->name;
    }

    //work方法简单实现
    public function work()
    {
        echo 'student working!';
    }
}

class EngineController implements Property
{
    //set方法
    public function setWeight($weight)
    {
        echo 'this is engine -> set weight';
    }

    public function setPrice($price)
    {
        echo "this is engine -> set price";
    }

    //work方法简单实现
    public function work()
    {
        echo 'engine working!';
    }
}

这里定义了两个相似类实现Property接口,同时都简单实现work()方法 StudentController类稍微不同,参数需要Person对象,同时我们可以使用文件来保存各个类的信息,我们也可以用成员属性代替.

class Run
{
   public static $mod_arr = [];
   public static $config = [
       'StudentController' => [
           'person' => 'xiao ming'
       ],
       'EngineController'  => [
           'weight' => '500kg',
           'price'  => '4000'
       ]
   ];

   //加载初始化
   public function __construct()
   {
       $config = self::$config;
       //用于检查是不是实现类
       $property = new ReflectionClass('Property');
       foreach ($config as $class_name => $params) {
           $class_reflect = new ReflectionClass($class_name);
           if(!$class_reflect->isSubclassOf($property)) {//用isSubclassOf方法检查是否是这个对象
               echo 'this is  error';
               continue;
           }

           //得到类的信息
           $class_obj = $class_reflect->newInstance();
           $class_method = $class_reflect->getMethods();

           foreach ($class_method as $method_name) {
               $this->handle_method($class_obj, $method_name, $params);
           }
           array_push(self::$mod_arr, $class_obj);
       }
   }

   //处理方法调用
   public function handle_method(Property $class_obj, ReflectionMethod $method_name, $params)
   {
       $m_name = $method_name->getName();
       $args = $method_name->getParameters();

       if(count($args) != 1 || substr($m_name, 0, 3) != 'set') {    
           return false;
       }
       //大小写转换,做容错处理
       $property = strtolower(substr($m_name, 3));
     
       if(!isset($params[$property])) {
           return false;
       }

       $args_class = $args[0]->getClass();
       echo '<pre>';
       if(empty($args_class)) {
           $method_name->invoke($class_obj, $params[$property]); //如果得到的类为空证明需要传递基础类型参数
       } else {
           $method_name->invoke($class_obj, $args_class->newInstance($params[$property])); //如果不为空说明需要传递真实对象
       }
   }
}

//程序开始
new Run();

到此程序结束,Run启动会自动调用构造方法,初始化要加载类库的其他成员属性,包括初始化和执行相应方法操作,这里只是完成了对应的set方法。其中$mod_arr属性保存了所有调用类的对象,每个对象包含数据,可以遍历包含的对象来以此调用work()方法。

程序只做辅助理解反射PAI用,各个功能没有完善,里面用到了好多反射API的类,方法,下面会有各个方法的总结。

反射API提供的常用类和函数:

下面提供的函数是常用的函数,不是全部,有的函数根本用不到,所以我们有往撒谎那个写,想看全部的可以到网上搜一下,比较多。

1:Reflection
  public static export(Reflector r [,bool return])//打印类或方法的详细信息
  public static  getModifierNames(int modifiers)  //取得修饰符的名字

2:ReflectionMethod:
    public static string export()                       //打印该方法的信息
    public mixed invoke(stdclass object, mixed* args)   //调用对应的方法
    public mixed invokeArgs(stdclass object, array args)//调用对应的方法,传多参数
    public bool isFinal()        //方法是否为final
    public bool isAbstract()     //方法是否为abstract
    public bool isPublic()       //方法是否为public
    public bool isPrivate()      //方法是否为private
    public bool isProtected()    //方法是否为protected
    public bool isStatic()       //方法是否为static
    public bool isConstructor()  //方法是否为构造函数

3:ReflectionClass:
    public static string export()  //打印类的详细信息
    public string getName()        //取得类名或接口名
    public bool isInternal()       //类是否为系统内部类
    public bool isUserDefined()    //类是否为用户自定义类
    public bool isInstantiable()   //类是否被实例化过
    public bool hasMethod(string name)  //类是否有特定的方法
    public bool hasProperty(string name)//类是否有特定的属性
    public string getFileName()         //获取定义该类的文件名,包括路径名
    public int getStartLine()           //获取定义该类的开始行
    public int getEndLine()             //获取定义该类的结束行
    public string getDocComment()       //获取该类的注释
    public ReflectionMethod getConstructor()           //取得该类的构造函数信息
    public ReflectionMethod getMethod(string name)     //取得该类的某个特定的方法信息
    public ReflectionMethod[] getMethods()             //取得该类的所有的方法信息
    public ReflectionProperty getProperty(string name) //取得某个特定的属性信息
    public ReflectionProperty[] getProperties()        //取得该类的所有属性信息
    public array getConstants()                        //取得该类所有常量信息
    public mixed getConstant(string name)              //取得该类特定常量信息
    public ReflectionClass[] getInterfaces()           //取得接口类信息
    public bool isInterface()  //测试该类是否为接口
    public bool isAbstract()   //测试该类是否为抽象类

4:ReflectionParameter:
    public static string export()     //导出该参数的详细信息
    public string getName()           //取得参数名
    public bool isPassedByReference() //测试该参数是否通过引用传递参数
    public ReflectionClass getClass() //若该参数为对象,返回该对象的类名
    public bool isArray()             //测试该参数是否为数组类型
    public bool allowsNull()          //测试该参数是否允许为空
    public bool isOptional()          //测试该参数是否为可选的,当有默认参数时可选
    public bool isDefaultValueAvailable() //测试该参数是否为默认参数
    public mixed getDefaultValue()        //取得该参数的默认值

5:ReflectionExtension类
    public static  export()    //导出该扩展的所有信息
    public string getName()    //取得该扩展的名字
    public string getVersion() //取得该扩展的版本
    public ReflectionFunction[] getFunctions()   //取得该扩展的所有函数
    public array getConstants()  //取得该扩展的所有常量
    public array getINIEntries() //取得与该扩展相关的,在php.ini中的指令信息
}

参考:

PHP: 反射 - Manual​www.php.net

参考:https://zhuanlan.zhihu.com/p/52915654

发表评论

登录后才能评论

评论列表(0条)