It has a complete reflection API and adds the ability to reverse engineer classes, interfaces, functions, methods and extensions. In addition, the reflection API provides a way to extract document annotations from functions, classes, and methods.
Note that some of the internal API s are missing the code needed for reflection extension work. For example, a built-in PHP class may lose data about reflection attributes. These few cases are considered errors, but for that reason, they should be discovered and repaired.
Knowing the structure of the human body and the distribution of the true Qi in the body, you can guide the true Qi to the finger, and train it into a Yangzhi, Six-Vein Sword, Flip-finger Shentong, Nine-Yin White Bone Claw, etc. You can also let the true Qi converge, break through Ren Du's two veins, and open a hole in the sky. You can also reverse the whole body meridians and practice toad meridians. The benefits of introspection are evident.
What's the benefit of reflection in letting the code perceive its own structure? Reflection API provides three capabilities for code manipulation at runtime:
- Set access control: setAccessible. Private methods/attributes are available. Note: SetAccessible only allows method / member variables to invoke/getValue/setValue, and does not represent a change in access rights defined by the class.
- Call function/method: invoke/invokeArgs. With API to obtain function parameters, it can safely transfer parameters and call functions, an enhanced version of call_user_func(_array);
- Generate instances independent of constructors: new Instance Without Constructor.
To illustrate the function of reflection API in a singleton, the singleton class code is as follows:
# foo.php class Foo { private static $id; private static $instance; private function __construct() { ++ self::$id; fwrite(STDOUT, "construct, instance id: " . self::$id . "\n"); } public static function getSingleton() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } }
In the Foo class, the constructor is private, the instance can be retrieved only through the getSingleton method, and the singleton is retrieved. However, under the support of reflection API, multiple instances can be obtained:
$instance1 = Foo::getSingleton(); var_dump($instance1); $class = new ReflectionClass("Foo"); $constructor = $class->getConstructor(); if ((ReflectionProperty::IS_PUBLIC & $constructor->getModifiers()) === 0) { $constructor->setAccessible(true); } $instance2 = $class->newInstanceWithoutConstructor(); $constructor->invoke($instance2); var_dump($instance2); # Script execution results construct, instance id: 1 object(Foo)#1 (0) { } construct, instance id: 2 object(Foo)#4 (0) { }
We successfully generated two instances and called the constructor to initialize the object. This is almost impossible without a reflection API.
Some Classes of Reflective API
class | Description |
Reflection | Provide static function export() for summary information of classes |
ReflectionClass | Class information and tools |
ReflectionMethod | Class Method Information and Tools |
ReflectionParameter | Method parameter information |
ReflectionProperty | Class attribute information |
ReflectionFunction | Functional information and tools |
ReflectionExtension | PHP Extension Information |
ReflectionException | Error class |
Using reflection API classes, we can get information about extensions to access objects, functions, and scripts at runtime. This information can be used to analyze classes or build frameworks.
Getting Class Information
We have used some functions to check class attributes in our work, such as get_class_methods, getProduct, etc. These methods have great limitations in obtaining detailed class information.
We can get information about the class by reflecting the static method export provided by API classes: Reflection and ReflectionClass. Export can provide almost all information about the class, including access control status of attributes and methods, parameters required by each method, and the location of each method in the script document. The output of the export static method is the same for the two tool classes, but in different ways.
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 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 many tools and methods. The official manual gives the following list:
ReflectionClass::__construct — Initialization ReflectionClass class ReflectionClass::export — Export a class ReflectionClass::getConstant — Gets a defined constant ReflectionClass::getConstants — Get a set of constants ReflectionClass::getConstructor — Get the constructor of the class ReflectionClass::getDefaultProperties — Get default properties ReflectionClass::getDocComment — Obtain document annotations ReflectionClass::getEndLine — Get the number of rows in the last row ReflectionClass::getExtension — Get the extension based on the defined class ReflectionExtension object ReflectionClass::getExtensionName — Gets the name of the extension where the defined class resides ReflectionClass::getFileName — Get the file name of the defined class ReflectionClass::getInterfaceNames — Access interface( interface)Name ReflectionClass::getInterfaces — Get interface ReflectionClass::getMethod — Getting a class method's ReflectionMethod. ReflectionClass::getMethods — Get an array of methods ReflectionClass::getModifiers — Get modifiers for classes ReflectionClass::getName — Get class name ReflectionClass::getNamespaceName — Get the name of the namespace ReflectionClass::getParentClass — Get parent class ReflectionClass::getProperties — Get a set of attributes ReflectionClass::getProperty — Getting an attribute of a class ReflectionProperty ReflectionClass::getReflectionConstant — Gets a ReflectionClassConstant for a class's constant ReflectionClass::getReflectionConstants — Gets class constants ReflectionClass::getShortName — Get short name ReflectionClass::getStartLine — Get the starting line number ReflectionClass::getStaticProperties — Getting static( static)attribute ReflectionClass::getStaticPropertyValue — Getting static( static)Attribute value ReflectionClass::getTraitAliases — Return trait An array of aliases ReflectionClass::getTraitNames — Returns the class used traits An array of names ReflectionClass::getTraits — Returns what is used by this class traits array ReflectionClass::hasConstant — Check that constants are defined ReflectionClass::hasMethod — Check if the method is defined ReflectionClass::hasProperty — Check whether properties are defined ReflectionClass::implementsInterface — Implementation of Interface ReflectionClass::inNamespace — Check if you are in a namespace ReflectionClass::isAbstract — Check whether a class is an abstract class( abstract) ReflectionClass::isAnonymous — Check if the class is anonymous ReflectionClass::isCloneable — Returns whether a class is replicable ReflectionClass::isFinal — Check whether the class is declared as final ReflectionClass::isInstance — Checking an instance of a class ReflectionClass::isInstantiable — Check whether classes can be instantiated ReflectionClass::isInterface — Check if the class is an interface( interface) ReflectionClass::isInternal — Check whether classes are internally defined by extensions or cores ReflectionClass::isIterateable — Check for iteration( iterateable) ReflectionClass::isSubclassOf — Check if it is a subclass ReflectionClass::isTrait — Has returned whether it is a single trait ReflectionClass::isUserDefined — Check if it is user-defined ReflectionClass::newInstance — Create a new class instance from the specified parameter ReflectionClass::newInstanceArgs — Create a new class instance from the given parameters. ReflectionClass::newInstanceWithoutConstructor — Create a new class instance without calling its constructor ReflectionClass::setStaticPropertyValue — Setting the value of static properties ReflectionClass::__toString — Return ReflectionClass Representation of object strings.
Use Reflection::export() to get 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 you create the ReflectionClass object, you can use the ReflectionTool class to output information about the Student class. Reflection::export() can format and output instances of any class that implements the Reflector interface.
Check class
The RelectionClass toolkit class we learned earlier provides a lot of toolkit methods for getting information about classes. For example, we can get the type of Student class and whether it can be instantiated or not.
Instrumental function
function classData(ReflectionClass $class) { $details = ''; $name = $class->getName(); // Returns the class name to be checked if ($class->isUserDefined()) { // Check whether the class is user-defined $details .= "$name is user defined" . PHP_EOL; } if ($class->isInternal()) { // Check whether classes are internally defined by extensions or cores $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 whether a class is an abstract class $details .= "$name is an abstract class" . PHP_EOL; } if ($class->isFinal()) { // Check whether the class is declared final $details .= "$name is a final class" . PHP_EOL; } if ($class->isInstantiable()) { // Check whether classes can be instantiated $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 results
Student is user defined Student can be instantiated
In addition to obtaining information about classes, ReflectionClass objects can also provide source code information such as the file name of the custom class and the start and end lines of the class in the file.
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 a file $from = $class->getStartLine(); // Provide the starting line of the class $to = $class->getEndLine(); // Termination rows for providing classes $len = $to - $from + 1; return implode(array_slice($lines, $from - 1, $len)); } $prodClass = new ReflectionClass('Student'); var_dump(getClassSource($prodClass));
Print results
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 and should check parameters and result codes in practice.
Inspection method
Similar to checking classes, ReflectionMethod objects can be used to check methods in classes.
There are two ways to obtain ReflectionMethod objects:
The first is to get an array of ReflectionMethod objects through ReflectionClass::getMethods(), which has the advantage of returning ReflectionMethod objects for all methods in the class without knowing the method name in advance.
The second is to instantiate objects directly using ReflectionMethod classes, which can only get one class method object and need to know the method name in advance.
Tool methods for ReflectionMethod objects:
ReflectionMethod::__construct — ReflectionMethod Constructive function ReflectionMethod::export — Output a callback method ReflectionMethod::getClosure — Returns a dynamically established method invocation interface. Translator's Note: This return value can be used to invoke private methods directly. ReflectionMethod::getDeclaringClass — Getting the class representation of reflection function call parameters ReflectionMethod::getModifiers — Get modifiers for methods ReflectionMethod::getPrototype — Return method prototype (If exist) ReflectionMethod::invoke — Invoke ReflectionMethod::invokeArgs — Parametric execution ReflectionMethod::isAbstract — Judging whether a method is abstract ReflectionMethod::isConstructor — Judging whether a method is a construction method ReflectionMethod::isDestructor — Judging whether a method is a destructive method ReflectionMethod::isFinal — Judgment method is negative meaning final ReflectionMethod::isPrivate — Judging whether a method is private ReflectionMethod::isProtected — Judging whether a method is a protection method (protected) ReflectionMethod::isPublic — Whether the judgment method is public or not ReflectionMethod::isStatic — Judging whether a method is static ReflectionMethod::setAccessible — Set whether the method is accessible ReflectionMethod::__toString — String representation of return reflection method objects
ReflectionClass::getMethods()
We can get an array of ReflectionMethod objects through ReflectionClass::getMethods().
$prodClass = new ReflectionClass('Student'); $methods = $prodClass->getMethods(); var_dump($methods);
Print results
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]
You can see that we have an array of ReflectionMethod objects for Student, each element being an object with two common attributes, name being the method name and class being the class to which it belongs. We can call object methods to get information about methods.
ReflectionMethod
Use the ReflectionMethod class directly to get information about class methods
$method = new ReflectionMethod('Student', 'setName'); var_dump($method);
Print results
object(ReflectionMethod)[1] public 'name' => string 'setName' (length=7) public 'class' => string 'Student' (length=7)
Be careful
In PHP 5, ReflectionMethod::retursReference() does not return true if the checked method only returns the object (even if the object is assigned or passed by reference). ReflectionMethod::returnsReference() returns true only if the method being detected has been explicitly declared to return a reference (with A & sign in front of the method name).
Check method parameters
In PHP 5, declaring class methods can limit the type of objects in parameters, so it is necessary to check the parameters of methods.
Similar to checking methods, ReflectionParameter objects can be used to check methods in classes. This object can tell you the name of parameters, whether variables can be passed by reference, and whether parameter type prompts and methods accept null values as parameters.
There are two ways to get the ReflectionParameter object, which is very similar to getting the ReflectionMethod object:
The first is to return the ReflectionParameter object array through the ReflectionMethod::getParameters() method, which can obtain all the parameter objects of a method.
The second is to instantiate the object directly using ReflectionParameter class, which can only get the object with a single parameter.
Tool methods for ReflectionParameter objects:
rameter::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'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'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()
With the same acquisition method, this method returns an array containing ReflectionParameter objects for each parameter of the method.
$method = new ReflectionMethod('Student', 'setName'); $params = $method->getParameters(); var_dump($params);
Print results
array (size=1) 0 => & object(ReflectionParameter)[2] public 'name' => string 'name' (length=4)
ReflectionParameter
Let's take a look at this approach. For a better understanding, I'll modify the setName method of the Student class and add two parameters a, b.
... public function setName($name, $a, $b) { $this->name = $name; } ...
Let's first look at the construction of ReflectionParameter classes
public ReflectionParameter::__construct ( string $function , string $parameter )
You can see that this class is instantiated with two parameters:
$function: When you need to get a function as a public function, just pass the name of the function. When the function is a class method, you need to pass an array in the form of array ('class','function').
$parameter: This parameter can be passed in two ways: the first is the parameter name (without a $symbol), and the second is the parameter index. Note: Whether the parameter name or index, the parameter must exist, otherwise it will be wrong.
The following examples are given:
$params = new ReflectionParameter(array('Student', 'setName'), 1); var_dump($params);
Print results
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 results
object(ReflectionParameter)[2] public 'name' => string 'c' (length=1)
epilogue
The reflection API of php is very powerful, it can get the detailed information of a class. Module objects can be dynamically invoked by writing a class through the reflection API, which is free to load third-party plug-ins and integrate into existing systems. There is no need to hard-code third-party code into the original code. Although reflection is seldom used in actual development, understanding reflection API is very helpful for understanding code structure and developing business patterns.