API отражения в PHP похож на пакет java.lang.reflect в Java. Он состоит из ряда встроенных классов, которые могут анализировать свойства, методы и классы. В некоторых отношениях она похожа на объектные функции, такие как get_class_vars(), но более гибкая и может предоставить больше информации. API отражения также работает с последними объектно-ориентированными функциями PHP, такими как управление доступом, интерфейсы и абстрактные классы. Функции старых классов не так просто использовать с этими новыми возможностями. Друзья, которые читали исходный код фреймворка, должны иметь определенное представление о механизме отражения PHP, таком как внедрение зависимостей, пул объектов, загрузка классов, некоторые шаблоны проектирования и т. д., все используют механизм отражения.
1. Некоторые классы API отражения
своего рода | описывать |
Reflection | Предоставьте статическую функцию export() для сводной информации о классе. |
ReflectionClass | Информация о классе и инструменты |
ReflectionMethod | Информация о методе класса и инструменты |
ReflectionParameter | Информация о параметрах метода |
ReflectionProperty | информация об атрибутах класса |
ReflectionFunction | Информация о функциях и инструменты |
ReflectionExtension | Информация о расширении PHP |
ReflectionException | класс ошибки |
Используя API отражения этих классов, мы можем получить информацию о доступе к объектам, функциям и расширениям в скриптах во время выполнения. Мы можем использовать эту информацию для анализа классов или конструкций сборки.
2. Получить информацию о классе
В своей работе мы использовали некоторые функции для проверки атрибутов класса, такие как: get_class_methods, getProduct и т.д. Эти методы имеют существенные ограничения для получения подробной информации о классе.
Мы можем получить информацию, связанную с классом, через класс API отражения: экспорт статического метода, предоставляемый Reflection и ReflectionClass, Экспорт может предоставить почти всю информацию о классе, включая статус контроля доступа к свойствам и методам, параметры, необходимые для каждого метода, и параметры каждого метода Расположение метода в документе скрипта. Для этих двух классов инструментов выходные результаты статического метода экспорта одинаковы, но используются они по-разному.
Сначала создайте простой класс
1 <?php
2
3 class Student {
4 public $name;
5 protected $age;
6 private $sex;
7
8 public function __construct($name, $age, $sex)
9 {
10 $this->setName($name);
11 $this->setAge($age);
12 $this->setSex($sex);
13 }
14
15 public function setName($name)
16 {
17 $this->name = $name;
18 }
19
20 protected function setAge($age)
21 {
22 $this->age = $age;
23 }
24
25 private function setSex($sex)
26 {
27 $this->sex = $sex;
28 }
29 }
2.1 Используйте ReflectionClass::export() для получения информации о классе
ReflectionClass::export('Student');
распечатать результат:
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 ]
}
}
}
}
ReflectionClass :: Export () выводКласс RefluictionClass обеспечивает много инструментов и методов. Список, заданный официальным руководством, выглядит следующим образом:
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'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 对象字符串的表示形式。
ReflectionClass
2.2 Используйте Reflection::export() для получения информации о классе
$prodClass = new ReflectionClass('Student');
Reflection::export($prodClass);
распечатать результат
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 ]
}
}
}
}
Вывод Reflection::export()После создания объекта ReflectionClass вы можете использовать класс инструментов Reflection для вывода информации о классе Student. Reflection::export() может форматировать и экспортировать экземпляр любого класса, реализующего интерфейс Reflector.
3. Проверить класс
Из класса инструментов ReflectionClass, о котором мы узнали ранее, мы знаем, что этот класс предоставляет множество методов инструментов для получения информации о классе. Например, мы можем получить тип класса Student, можно ли его инстанцировать
Вспомогательная функция
function classData(ReflectionClass $class) {
$details = '';
$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('Student');
print classData($prodClass);
распечатать результат
Student is user defined
Student can be instantiated
В дополнение к получению соответствующей информации о классе вы также можете получить соответствующую информацию об исходном коде, такую как имя файла, в котором пользовательский класс предоставляется объектом ReflectionClass, а также начальную и конечную строки класса в файле.
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('Student');
var_dump(getClassSource($prodClass));
распечатать результат
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)
Мы видели, что getClassSource принимает в качестве параметра объект ReflectionClass и возвращает исходный код соответствующего класса. Эта функция игнорирует обработку ошибок, на практике следует проверять аргументы и коды результатов!
4. Метод проверки
Подобно проверке классов, объекты ReflectionMethod можно использовать для проверки методов в классах.
Есть два способа получить объект ReflectionMethod:
Первый — получить массив объектов ReflectionMethod через ReflectionClass::getMethods() Преимущество этого метода в том, что вам не нужно заранее знать имя метода, и вы вернете объекты ReflectionMethod всех методов в классе.
Во-вторых, напрямую использовать класс ReflectionMethod для создания экземпляра объекта.Таким образом, можно получить только один объект метода класса, и имя метода должно быть известно заранее.
Служебный метод объекта ReflectionMethod:
ReflectionMethod::__construct — ReflectionMethod 的构造函数
ReflectionMethod::export — 输出一个回调方法
ReflectionMethod::getClosure — 返回一个动态建立的方法调用接口,译者注:可以使用这个返回值直接调用非公开方法。
ReflectionMethod::getDeclaringClass — 获取反射函数调用参数的类表达
ReflectionMethod::getModifiers — 获取方法的修饰符
ReflectionMethod::getPrototype — 返回方法原型 (如果存在)
ReflectionMethod::invoke — Invoke
ReflectionMethod::invokeArgs — 带参数执行
ReflectionMethod::isAbstract — 判断方法是否是抽象方法
ReflectionMethod::isConstructor — 判断方法是否是构造方法
ReflectionMethod::isDestructor — 判断方法是否是析构方法
ReflectionMethod::isFinal — 判断方法是否定义 final
ReflectionMethod::isPrivate — 判断方法是否是私有方法
ReflectionMethod::isProtected — 判断方法是否是保护方法 (protected)
ReflectionMethod::isPublic — 判断方法是否是公开方法
ReflectionMethod::isStatic — 判断方法是否是静态方法
ReflectionMethod::setAccessible — 设置方法是否访问
ReflectionMethod::__toString — 返回反射方法对象的字符串表达
ReflectionMethod
4.1 ReflectionClass::getMethods()
Мы можем получить массив объектов ReflectionMethod через ReflectionClass::getMethods().
$prodClass = new ReflectionClass('Student');
$methods = $prodClass->getMethods();
var_dump($methods);
распечатать результат
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)
Вы можете видеть, что мы получили массив объектов Student's ReflectionMethod, каждый элемент которого представляет собой объект, который имеет два общедоступных свойства, name — это имя метода, а class — это класс, к которому он принадлежит. Мы можем вызывать методы объекта, чтобы получить информацию о методах.
4.2 ReflectionMethod
Напрямую используйте класс ReflectionMethod для получения информации о методах класса.
$method = new ReflectionMethod('Student', 'setName');
var_dump($method);
распечатать результат
object(ReflectionMethod)[1]
public 'name' => string 'setName' (length=7)
public 'class' => string 'Student' (length=7)
4.3 Внимание
В PHP5 ReflectionMethod::retursReference() не вернет true, если проверяемый метод возвращает только объект (даже если объект присваивается или передается по ссылке). ReflectionMethod::returnsReference() возвращает значение true, только если инструментированный метод был явно объявлен для возврата ссылки (с амперсандом перед именем метода).
5. Проверьте параметры метода
В PHP5 тип объекта в параметре может быть ограничен при объявлении метода класса, поэтому возникает необходимость проверки параметров метода.
Подобно проверке методов, объект ReflectionParameter можно использовать для проверки методов в классе.Этот объект может сообщить вам имя параметра, может ли переменная быть передана по ссылке, он также может дать вам подсказки типа параметра и является ли метод принимает null в качестве параметра.
Есть два способа получить объект ReflectionParameter, что очень похоже на получение объекта ReflectionMethod:
Первый — вернуть массив объектов ReflectionParameter с помощью метода ReflectionMethod::getParameters(), который может получить все объекты параметров метода.
Второй — напрямую использовать класс 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'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
ReflectionParameter
5.1 ReflectionMethod::getParameters()
Как и метод get, этот метод возвращает массив, содержащий объекты ReflectionParameter для каждого параметра метода.
$method = new ReflectionMethod('Student', 'setName');
$params = $method->getParameters();
var_dump($params);
распечатать результат
array (size=1)
0 => &
object(ReflectionParameter)[2]
public 'name' => string 'name' (length=4)
5.2 ReflectionParameter
Давайте посмотрим на этот метод.Для лучшего понимания я изменю метод setName класса Student и добавлю два параметра a, b
...
public function setName($name, $a, $b)
{
$this->name = $name;
}
...
Во-первых, давайте взглянем на конструктор класса ReflectionParameter.
public ReflectionParameter::__construct ( string $function , string $parameter )
Вы можете видеть, что класс получает два параметра при создании экземпляра:
$функция: когда вам нужно получить функцию как общедоступную, вам нужно только передать имя функции. Когда функция является методом класса, вам нужно передать массив в формате: массив('класс', 'функция').
$parameter: этот параметр можно передать двумя способами: первый — это имя параметра (без знака $), а второй — индекс параметра. Примечание. Будь то имя параметра или индекс, параметр должен существовать, иначе будет сообщено об ошибке.
Следующий пример:
$params = new ReflectionParameter(array('Student', 'setName'), 1);
var_dump($params);
распечатать результат
object(ReflectionParameter)[1]
public 'name' => string 'a' (length=1)
Давайте определим другую функцию для тестирования
function foo($a, $b, $c) { }
$reflect = new ReflectionParameter('foo', 'c');
var_dump($reflect);
распечатать результат
object(ReflectionParameter)[2]
public 'name' => string 'c' (length=1)
6. Заключение
API отражения PHP очень мощный, он может получить подробную информацию о классе. Мы можем использовать API отражения, чтобы написать класс для динамического вызова объекта модуля, который может свободно загружать сторонние плагины и интегрироваться в существующую систему. Нет необходимости жестко встраивать сторонний код в исходный код. Хотя отражение редко используется в реальной разработке, понимание API отражения очень полезно для понимания структуры кода и разработки бизнес-моделей в работе. Этот пост в блоге писался от случая к случаю в течение длительного времени (в основном лень!), если есть какие-либо ошибки или недостатки, пожалуйста, поправьте меня, предложения! !