Detailed explanation of PHP reflection API

The reflection API in PHP is like the java.lang.reflect package in Java. It consists of a series of built-in classes that can analyze properties, methods and classes. It is similar in some respects 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. The old class functions are not as easy to use with these new features. Friends who have seen the source code of the framework should have a certain understanding of the reflection mechanism of PHP, such as dependency injection, object pool, class loading, some design patterns, etc., all use the reflection mechanism.

Partial classes of the reflection API

Using these classes in the Reflection API, it is possible to gain access to extended information about objects, functions, and scripts at runtime. This information can be used to analyze classes or build frameworks.

kind describe
Reflection Provides the static function export() for summary information of the class
ReflectionClass Class Information and Tools
ReflectionMethod Class Method Information and Tools
ReflectionParameter Method parameter information
ReflectionProperty class attribute information
ReflectionFunction Function Information and Tools
ReflectionExtension PHP extension information
ReflectionException error class

Get class information

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

We can get information about the class through the reflection API class: the static method export provided by Reflection and ReflectionClass. export can provide almost all information about the class, including the access control status of attributes and methods, the parameters required by each method, and each The position of the method in the script document. The output of the export static method of these two tool classes is the same, but the usage is 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 get class information

ReflectionClass::export('Student');

Print result:

 ReflectionClass::export() output

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

 ReflectionClass

Use Reflection::export() to get class information 

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

print result

 Reflection::export() output

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

check class

The ReflectionClass tool class we learned earlier knows that this class provides a lot of tool methods for obtaining class information. For example, we can get the type of the Student class, whether it can be instantiated

Tool function

function classData(ReflectionClass $class) { 
    $details = ''; 
    $name = $class->getName(); // return the class name to check 
    if ($class->isUserDefined()) { // check if the class is defined by User defined 
        $details .= "$name is user defined" . PHP_EOL; 
    } 
    if ($class->isInternal()) { // Check if class is defined internally by extension or core 
        $details .= "$name is built- in" . PHP_EOL; 
    } 
    if ($class->isInterface()) { // Check if the class is an interface 
        $details .= "$name is interface" . PHP_EOL; 
    } 
    if ($class->isAbstract()) { // Check if class is abstract 
        $details .= "$name is an abstract class" . PHP_EOL; 
    }  
    if ($class->isFinal()) { // Check if the class is declared final
        $details .= "$name is a final class" . PHP_EOL;
    } 
    if ($class->isInstantiable()) { // Check if the class is instantiable 
        $details .= "$name can be instantiated" . PHP_EOL; 
    } else { 
        $details .= "$name can not be instantiated" . PHP_EOL; 
    } 
    return $details; 
} 

$prodClass = new ReflectionClass('Student'); 
print classData($prodClass);

print result

Student is user defined
Student can be instantiated

In addition to obtaining the relevant information of the class, you can also obtain the relevant source code information such as the file name of the custom class and the start and end lines of the class in the file provided by the ReflectionClass object.

function getClassSource(ReflectionClass $class) { 
    $path = $class->getFileName(); // Get the absolute path of the class file 
    $lines = @file($path); // Get an array of all lines in the file 
    $from = $class->getStartLine(); // Provide the start line of the class 
    $to = $class->getEndLine(); // Provide the end line of the class 
    $len = $to - $from + 1; 
    return implode(array_slice ($lines, $from - 1, $len)); 
} 

$prodClass = new ReflectionClass('Student'); 
var_dump(getClassSource($prodClass)); 

print result 
string '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;
    }
}
' (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 arguments and result codes should be checked!

Inspection Method

Similar to inspecting classes, ReflectionMethod objects can be used to inspect methods in classes.

There are two ways to obtain a ReflectionMethod object:

The first is to obtain an array of ReflectionMethod objects through ReflectionClass::getMethods(). The advantage of this method is that it does not need to know the method name in advance, and it will return the ReflectionMethod objects of all methods in the class.

The second is to instantiate the object directly using the ReflectionMethod class. In this way, only one class method object can be obtained, and the method name needs to be known in advance.

Utility methods for ReflectionMethod objects:

 ReflectionMethod

ReflectionClass::getMethods()

We can get an array of ReflectionMethod objects through ReflectionClass::getMethods().

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

print result

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

It can be seen that we have obtained the Student's ReflectionMethod object array, each element is an object, which has two public properties, name is the method name, and class is the class to which it belongs. We can call object methods to get method information.

ReflectionMethod

Directly use the ReflectionMethod class to get information about class methods

$method = new ReflectionMethod('Student', 'setName');
var_dump($method);

print result

object(ReflectionMethod)[1]
  public 'name' => string 'setName' (length=7)
  public 'class' => string 'Student' (length=7)

Notice

In PHP5, ReflectionMethod::retursReference() will not return true if the inspected method only returns objects (even if objects are assigned or passed by reference). ReflectionMethod::returnsReference() returns true only if the inspected method has been explicitly declared to return references (with an & symbol preceding the method name).

Check method parameters

In PHP5, when declaring a class method, you can restrict the type of object in the parameter, so it becomes necessary to check the parameters of the method.

Similar to inspecting methods, a ReflectionParameter object can be used to inspect methods in a class. This object can tell you the name of the parameter, whether the variable can be passed by reference, and also tells you about parameter type hints and whether the method accepts null values ​​as parameters.

There are also two ways to obtain ReflectionParameter objects, which are very similar to obtaining ReflectionMethod objects:

The first is to return an array of ReflectionParameter objects through the ReflectionMethod::getParameters() method, which can get all the parameter objects of a method.

The second is to directly use the ReflectionParameter class to instantiate and obtain objects. This method can only obtain objects with a single parameter.

Utility methods for ReflectionParameter objects:

 ReflectionParameter

ReflectionMethod::getParameters()

Same as get method, this method will return an array containing ReflectionParameter objects for each parameter of the method

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

print result

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

ReflectionParameter

Let's take a look at this method. For a better understanding, I modify the setName method of the Student class and add two parameters a, b

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

First, let's look at the construction method of the ReflectionParameter class

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

You can see that the class receives two parameters when it is instantiated:

$function: When you need to obtain a function as a public function, you only need to pass the function name. When the function is a class method, an array needs to be passed in the format: array('class', 'function').

$parameter: This parameter can be passed in two ways, the first is the parameter name (without the $ symbol), and the second is the parameter index. Note: Whether it is a parameter name or an index, the parameter must exist, otherwise an error will be reported.

Here is an example:

$params = new ReflectionParameter(array('Student', 'setName'), 1);
var_dump($params);

print result

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

Let's define another function to test

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

print result

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

epilogue

PHP's reflection API is very powerful, it can get the detailed information of a class. We can write a class through the reflection API to dynamically call the Module object, which can freely load third-party plug-ins and integrate them into existing systems. There is no need to hard-code third-party code into the original code. Although the use of reflection in actual development is relatively small, understanding the reflection API is very helpful for understanding the code structure and developing business models at work. This blog post has been written intermittently for a long time (mainly because of laziness!), if there are any mistakes and deficiencies, please correct me and suggest! !

Guess you like

Origin blog.csdn.net/Api_k/article/details/132120239