Home >Backend Development >PHP Tutorial >Learn more about the PHP Reflection API!

Learn more about the PHP Reflection API!

青灯夜游
青灯夜游forward
2020-07-24 17:01:342013browse

Learn more about the PHP Reflection API!

The reflection API in PHP is just like the java.lang.reflect package in Java. It consists of a set of built-in classes that can analyze properties, methods, and classes. It is similar in some ways to object functions, such as get_class_vars(), but is more flexible and can provide more information.

The reflection API also works with PHP's latest object-oriented features, such as access control, interfaces and abstract classes. Older class functions are less easy to use with these new features. Friends who have read the source code of the framework should have a certain understanding of PHP's reflection mechanism, such as dependency injection, object pooling, class loading, some design patterns, etc., all of which use reflection mechanisms.

Some classes of the Reflection API

Using these classes of the Reflection API, you can obtain runtime access to objects, functions, and extensions in scripts information. This information can be used to analyze classes or build frameworks.

Reflection Provide static function export() for class summary informationReflectionClassClass information and toolsReflectionMethodClass method information and toolsReflectionParameterMethod parameter informationReflectionPropertyClass attribute informationReflectionFunctionFunction information and tools##ReflectionExtensionReflectionException

Get class information

We have used some functions for checking class attributes in our work, such as: get_class_methods, getProduct, etc. These methods have significant limitations in obtaining detailed class information.

We can obtain relevant information about the class through the static method export provided by the reflection API class: Reflection and ReflectionClass. Export can provide almost all information about the class, including the access control status of attributes and methods, and each method. The parameters required and the location of each method in the script document. For these two tool classes, the output results of the export static method are the same, but the usage methods are different.

First, build a simple class

<?php

class Student {
    public    $name;
    protected $age;
    private   $sex;

    public function __construct($name, $age, $sex)
    {
        $this->setName($name);
        $this->setAge($age);
        $this->setSex($sex);
    }

    public function setName($name)
    {
       $this->name = $name;
    }

    protected function setAge($age)
    {
        $this->age = $age;
    }

    private function setSex($sex)
    {
        $this->sex = $sex;
    }
}

Use ReflectionClass::export() to obtain class information

ReflectionClass::export(&#39;Student&#39;);

Print results:

Class [ class Student ] {
    @@ D:\wamp\www\test2.php 3-29
    - Constants [0] { }
    - Static properties [0] { }
    - Static methods [0] { }
    - Properties [3] {
        Property [ public $name ]
        Property [ protected $age ]
        Property [ private $sex ]
    }
    - Methods [4] {
        Method [ public method __construct ] {
            @@ D:\wamp\www\test2.php 8 - 13
            - Parameters [3] {
                Parameter #0 [ $name ]
                Parameter #1 [ $age ]
                Parameter #2 [ $sex ]
            }
        }
        Method [ public method setName ] {
            @@ D:\wamp\www\test2.php 15 - 18
            - Parameters [1] {
                Parameter #0 [ $name ]
            }
        }
        Method [ protected method setAge ] {
            @@ D:\wamp\www\test2.php 20 - 23
            - Parameters [1] {
                Parameter #0 [ $age ]
            }
        }
        Method [ private method setSex ] {
            @@ D:\wamp\www\test2.php 25 - 28
            - Parameters [1] {
                Parameter #0 [ $sex ]
            }
        }
    }
}

The ReflectionClass class provides a lot of tool methods. The list given in the official manual is as follows:

ReflectionClass::__construct — 初始化 ReflectionClass 类
ReflectionClass::export — 导出一个类
ReflectionClass::getConstant — 获取定义过的一个常量
ReflectionClass::getConstants — 获取一组常量
ReflectionClass::getConstructor — 获取类的构造函数
ReflectionClass::getDefaultProperties — 获取默认属性
ReflectionClass::getDocComment — 获取文档注释
ReflectionClass::getEndLine — 获取最后一行的行数
ReflectionClass::getExtension — 根据已定义的类获取所在扩展的 ReflectionExtension 对象
ReflectionClass::getExtensionName — 获取定义的类所在的扩展的名称
ReflectionClass::getFileName — 获取定义类的文件名
ReflectionClass::getInterfaceNames — 获取接口(interface)名称
ReflectionClass::getInterfaces — 获取接口
ReflectionClass::getMethod — 获取一个类方法的 ReflectionMethod。
ReflectionClass::getMethods — 获取方法的数组
ReflectionClass::getModifiers — 获取类的修饰符
ReflectionClass::getName — 获取类名
ReflectionClass::getNamespaceName — 获取命名空间的名称
ReflectionClass::getParentClass — 获取父类
ReflectionClass::getProperties — 获取一组属性
ReflectionClass::getProperty — 获取类的一个属性的 ReflectionProperty
ReflectionClass::getReflectionConstant — Gets a ReflectionClassConstant for a class&#39;s constant
ReflectionClass::getReflectionConstants — Gets class constants
ReflectionClass::getShortName — 获取短名
ReflectionClass::getStartLine — 获取起始行号
ReflectionClass::getStaticProperties — 获取静态(static)属性
ReflectionClass::getStaticPropertyValue — 获取静态(static)属性的值
ReflectionClass::getTraitAliases — 返回 trait 别名的一个数组
ReflectionClass::getTraitNames — 返回这个类所使用 traits 的名称的数组
ReflectionClass::getTraits — 返回这个类所使用的 traits 数组
ReflectionClass::hasConstant — 检查常量是否已经定义
ReflectionClass::hasMethod — 检查方法是否已定义
ReflectionClass::hasProperty — 检查属性是否已定义
ReflectionClass::implementsInterface — 接口的实现
ReflectionClass::inNamespace — 检查是否位于命名空间中
ReflectionClass::isAbstract — 检查类是否是抽象类(abstract)
ReflectionClass::isAnonymous — 检查类是否是匿名类
ReflectionClass::isCloneable — 返回了一个类是否可复制
ReflectionClass::isFinal — 检查类是否声明为 final
ReflectionClass::isInstance — 检查类的实例
ReflectionClass::isInstantiable — 检查类是否可实例化
ReflectionClass::isInterface — 检查类是否是一个接口(interface)
ReflectionClass::isInternal — 检查类是否由扩展或核心在内部定义
ReflectionClass::isIterateable — 检查是否可迭代(iterateable)
ReflectionClass::isSubclassOf — 检查是否为一个子类
ReflectionClass::isTrait — 返回了是否为一个 trait
ReflectionClass::isUserDefined — 检查是否由用户定义的
ReflectionClass::newInstance — 从指定的参数创建一个新的类实例
ReflectionClass::newInstanceArgs — 从给出的参数创建一个新的类实例。
ReflectionClass::newInstanceWithoutConstructor — 创建一个新的类实例而不调用它的构造函数
ReflectionClass::setStaticPropertyValue — 设置静态属性的值
ReflectionClass::__toString — 返回 ReflectionClass 对象字符串的表示形式。

Use Reflection::export() to obtain Class information

$prodClass = new ReflectionClass('Student');
Reflection::export($prodClass);

Print results

Class [ class Student ] {
    @@ D:\wamp\www\test2.php 3-29
    - Constants [0] { }
    - Static properties [0] { }
    - Static methods [0] { }
    - Properties [3] {
        Property [ public $name ]
        Property [ protected $age ]
        Property [ private $sex ]
    }
    - Methods [4] {
        Method [ public method __construct ] {
            @@ D:\wamp\www\test2.php 8 - 13
            - Parameters [3] {
                Parameter #0 [ $name ]
                Parameter #1 [ $age ]
                Parameter #2 [ $sex ]
            }
        }
        Method [ public method setName ] {
            @@ D:\wamp\www\test2.php 15 - 18
            - Parameters [1] {
                Parameter #0 [ $name ]
            }
        }
        Method [ protected method setAge ] {
            @@ D:\wamp\www\test2.php 20 - 23
            - Parameters [1] {
                Parameter #0 [ $age ]
            }
        }
        Method [ private method setSex ] {
            @@ D:\wamp\www\test2.php 25 - 28
            - Parameters [1] {
                Parameter #0 [ $sex ]
            }
        }
    }
}

After creating the ReflectionClass object, you can use the Reflection tool class to output relevant information about the Student class. Reflection::export() can format and export instances of any class that implements the Reflector interface.

Check Class

#We learned about the ReflectionClass tool class earlier, and we know that this class provides many tool methods for obtaining class information. For example, we can get the type of Student class and whether it can be instantiated

Tool function

function classData(ReflectionClass $class) {
    $details = &#39;&#39;;
    $name = $class->getName();          // 返回要检查的类名
    if ($class->isUserDefined()) {      // 检查类是否由用户定义
        $details .= "$name is user defined" . PHP_EOL;
    }
    if ($class->isInternal()) {         // 检查类是否由扩展或核心在内部定义
        $details .= "$name is built-in" . PHP_EOL;
    }
    if ($class->isInterface()) {        // 检查类是否是一个接口
        $details .= "$name is interface" . PHP_EOL;
    }
    if ($class->isAbstract()) {         // 检查类是否是抽象类
        $details .= "$name is an abstract class" . PHP_EOL;
    }
    if ($class->isFinal()) {            // 检查类是否声明为 final
        $details .= "$name is a final class" . PHP_EOL;
    }
    if ($class->isInstantiable()) {     // 检查类是否可实例化
        $details .= "$name can be instantiated" . PHP_EOL;
    } else {
        $details .= "$name can not be instantiated" . PHP_EOL;
    }
    return $details;
}

$prodClass = new ReflectionClass(&#39;Student&#39;);
print classData($prodClass);

Print results

Student is user defined
Student can be instantiated

In addition to getting the relevant information of the class, we can also get the ReflectionClass The object provides relevant source code information such as the file name where the custom class is located and the starting and ending lines of the class in the file.

function getClassSource(ReflectionClass $class) {
    $path  = $class->getFileName();  // 获取类文件的绝对路径
    $lines = @file($path);           // 获得由文件中所有行组成的数组
    $from  = $class->getStartLine(); // 提供类的起始行
    $to    = $class->getEndLine();   // 提供类的终止行
    $len   = $to - $from + 1;
    return implode(array_slice($lines, $from - 1, $len));
}

$prodClass = new ReflectionClass(&#39;Student&#39;);
var_dump(getClassSource($prodClass));

Print results

string &#39;class Student {
    public    $name;
    protected $age;
    private   $sex;

    public function __construct($name, $age, $sex)
    {
        $this->setName($name);
        $this->setAge($age);
        $this->setSex($sex);
    }

    public function setName($name)
    {
        $this->name = $name;
    }

    protected function setAge($age)
    {
        $this->age = $age;
    }

    private function setSex($sex)
    {
        $this->sex = $sex;
    }
}
&#39; (length=486)

We see that getClassSource accepts a ReflectionClass object as its parameter and returns the source code of the corresponding class. This function ignores error handling, in practice the parameters and result code should be checked!

Checking methods

Similar to checking classes, ReflectionMethod objects can be used to check methods in a class.

There are two ways to obtain ReflectionMethod objects:

The first is to obtain an array of ReflectionMethod objects through ReflectionClass::getMethods(). The advantage of this method is that you do not need to know the method name in advance. Will return ReflectionMethod objects for all methods in the class.

The second method is to directly use the ReflectionMethod class to instantiate the object. This method can only obtain one class method object, and you need to know the method name in advance.

Utility methods of ReflectionMethod objects:

ReflectionMethod::__construct — Constructor of ReflectionMethod
ReflectionMethod::export — Export a callback method
ReflectionMethod::getClosure — Returns a dynamically created method calling interface. Translator's Note: You can use this return value to directly call non-public methods.
ReflectionMethod::getDeclaringClass — Get the class representation of the reflection function call parameters
ReflectionMethod::getModifiers — Get the modifiers of the method
ReflectionMethod::getPrototype — Return the method prototype (if present)
ReflectionMethod:: invoke — Invoke
ReflectionMethod::invokeArgs — Execute with parameters
ReflectionMethod::isAbstract — Determine whether the method is an abstract method
ReflectionMethod::isConstructor — Determine whether the method is a constructor
ReflectionMethod::isDestructor — Determine whether the method is a destructor method
ReflectionMethod::isFinal — Determine whether the method is defined as final
ReflectionMethod::isPrivate — Determine whether the method is a private method
ReflectionMethod::isProtected — Determine whether the method is a protected method (protected )
ReflectionMethod::isPublic — Determine whether the method is a public method
ReflectionMethod::isStatic — Determine whether the method is a static method
ReflectionMethod::setAccessible — Set whether the method is accessible
ReflectionMethod::__toString — Return The string expression of the reflection method object

ReflectionClass::getMethods()

We can obtain it through ReflectionClass::getMethods() Array of ReflectionMethod objects.

$prodClass = new ReflectionClass('Student');
$methods = $prodClass->getMethods();
var_dump($methods);

Print results

array (size=4)
  0 => &
    object(ReflectionMethod)[2]
      public &#39;name&#39; => string &#39;__construct&#39; (length=11)
      public &#39;class&#39; => string &#39;Student&#39; (length=7)
  1 => &
    object(ReflectionMethod)[3]
      public &#39;name&#39; => string &#39;setName&#39; (length=7)
      public &#39;class&#39; => string &#39;Student&#39; (length=7)
  2 => &
    object(ReflectionMethod)[4]
      public &#39;name&#39; => string &#39;setAge&#39; (length=6)
      public &#39;class&#39; => string &#39;Student&#39; (length=7)
  3 => &
    object(ReflectionMethod)[5]
      public &#39;name&#39; => string &#39;setSex&#39; (length=6)
      public &#39;class&#39; => string &#39;Student&#39; (length=7)

You can see that we have obtained the Student's ReflectionMethod object array. Each element is an object, which has two public attributes. name is the method name and class is Category. We can call object methods to obtain method information.

ReflectionMethod

Directly use the ReflectionMethod class to obtain information about class methods

$method = new ReflectionMethod(&#39;Student&#39;, &#39;setName&#39;);
var_dump($method);

Print results

object(ReflectionMethod)[1]
  public &#39;name&#39; => string &#39;setName&#39; (length=7)
  public &#39;class&#39; => string &#39;Student&#39; (length=7)

Notice

在PHP5中,如果被检查的方法只返回对象(即使对象是通过引用赋值或传递的),那么 ReflectionMethod::retursReference() 不会返回 true。只有当被检测的方法已经被明确声明返回引用(在方法名前面有&符号)时,ReflectionMethod::returnsReference() 才返回 true。

检查方法参数

在PHP5中,声明类方法时可以限制参数中对象的类型,因此检查方法的参数变得非常必要。

类似于检查方法,ReflectionParameter 对象可以用于检查类中的方法,该对象可以告诉你参数的名称,变量是否可以按引用传递,还可以告诉你参数类型提示和方法是否接受空值作为参数。

获得 ReflectionParameter 对象的方法有同样两种,这和获取 ReflectionMethod 对象非常类似:

第一种是通过 ReflectionMethod::getParameters() 方法返回 ReflectionParameter 对象数组,这种方法可以获取到一个方法的全部参数对象。

第二种是直接使用 ReflectionParameter  类实例化获取对象,这种方法只能获取到单一参数的对象。

ReflectionParameter 对象的工具方法:

ReflectionParameter::allowsNull — Checks if null is allowed
ReflectionParameter::canBePassedByValue — Returns whether this parameter can be passed by value
ReflectionParameter::__clone — Clone
ReflectionParameter::__construct — Construct
ReflectionParameter::export — Exports
ReflectionParameter::getClass — Get the type hinted class
ReflectionParameter::getDeclaringClass — Gets declaring class
ReflectionParameter::getDeclaringFunction — Gets declaring function
ReflectionParameter::getDefaultValue — Gets default parameter value
ReflectionParameter::getDefaultValueConstantName — Returns the default value&#39;s constant name if default value is constant or null
ReflectionParameter::getName — Gets parameter name
ReflectionParameter::getPosition — Gets parameter position
ReflectionParameter::getType — Gets a parameter&#39;s type
ReflectionParameter::hasType — Checks if parameter has a type
ReflectionParameter::isArray — Checks if parameter expects an array
ReflectionParameter::isCallable — Returns whether parameter MUST be callable
ReflectionParameter::isDefaultValueAvailable — Checks if a default value is available
ReflectionParameter::isDefaultValueConstant — Returns whether the default value of this parameter is constant
ReflectionParameter::isOptional — Checks if optional
ReflectionParameter::isPassedByReference — Checks if passed by reference
ReflectionParameter::isVariadic — Checks if the parameter is variadic
ReflectionParameter::__toString — To string

ReflectionMethod::getParameters()

同获取方法,此方法会返回一个数组,包含方法每个参数的 ReflectionParameter 对象

$method = new ReflectionMethod(&#39;Student&#39;, &#39;setName&#39;);
$params = $method->getParameters();
var_dump($params);

打印结果

array (size=1)
  0 => &
    object(ReflectionParameter)[2]
      public 'name' => string 'name' (length=4)

ReflectionParameter

我们来了解一下这种方式,为了更好的理解,我修改一下 Student 类的 setName方法,增加两个参数 a, b

...
    public function setName($name, $a, $b)
    {
        $this->name = $name;
    }
...

首先我们看一下 ReflectionParameter 类的构造方法

public ReflectionParameter::__construct ( string $function , string $parameter )

可以看到该类实例化时接收两个参数:

$function:当需要获取函数为公共函数时只需传函数名称即可。当该函数是某个类方法时,需要传递一个数组,格式为:array('class', 'function')。

$parameter:这个参数可以传递两种,第一种为参数名(无$符号),第二种为参数索引。注意:无论是参数名还是索引,该参数都必须存在,否则会报错。

下面举例:

$params = new ReflectionParameter(array(&#39;Student&#39;, &#39;setName&#39;), 1);
var_dump($params);

打印结果

object(ReflectionParameter)[1]
  public 'name' => string 'a' (length=1)

我们再定义一个函数测试一下

function foo($a, $b, $c) { }
$reflect = new ReflectionParameter(&#39;foo&#39;, &#39;c&#39;);
var_dump($reflect);

打印结果

object(ReflectionParameter)[2]
  public 'name' => string 'c' (length=1)

结语

php的反射API功能非常的强大,它可以将一个类的详细信息获取出来。我们可以通过反射API编写个类来动态调用Module对象,该类可以自由加载第三方插件并集成进已有的系统。而不需要把第三方的代码硬编码进原有的代码中。虽然实际开发中使用反射情况比较少,但了解反射API对工作中对代码结构的了解和开发业务模式帮助还是非常大的。此篇博文断断续续的写了很久(主要就是懒!),如有错误与不足欢迎指正,建议!!

相关教程推荐:《PHP教程

##Class Description
PHP Extended information
Error class

The above is the detailed content of Learn more about the PHP Reflection API!. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:cnblogs.com. If there is any infringement, please contact admin@php.cn delete