Reflection
Введение
В PHP 5 имеется полный набор Reflection API, который предоставляет
возможность проводить реверс-инжиниринг классов, интерфейсов, функций,
методов, а также расширений. В дополнение к этому, Reflection API
предоставляет средства для извлечения комментариев для функций, классов
и методов.
Reflection API - это объектно-ориентированное расширение для Zend Engine,
состоящее из следующих классов:
Замечание:
Более подробно эти классы рассматриваются в следующих главах.
Пример #1 Простой пример использования Reflection API
<?php Reflection::export(new ReflectionClass('Exception')); ?>
Результат выполнения данного примера:
Class [ <internal> class Exception ] {
- Constants [0] {
}
- Static properties [0] {
}
- Static methods [0] {
}
- Properties [6] {
Property [ <default> protected $message ]
Property [ <default> private $string ]
Property [ <default> protected $code ]
Property [ <default> protected $file ]
Property [ <default> protected $line ]
Property [ <default> private $trace ]
}
- Methods [9] {
Method [ <internal> final private method __clone ] {
}
Method [ <internal, ctor> public method __construct ] {
- Parameters [2] {
Parameter #0 [ <optional> $message ]
Parameter #1 [ <optional> $code ]
}
}
Method [ <internal> final public method getMessage ] {
}
Method [ <internal> final public method getCode ] {
}
Method [ <internal> final public method getFile ] {
}
Method [ <internal> final public method getLine ] {
}
Method [ <internal> final public method getTrace ] {
}
Method [ <internal> final public method getTraceAsString ] {
}
Method [ <internal> public method __toString ] {
}
}
}
Reflector
Reflector - это интерфейс, который реализуется
всеми экспортируемыми классами Reflection.
ReflectionException
ReflectionException наследует стандартный класс
Exception и выбрасывается
Reflection API, он не реализует никаких специальных методов или свойств.
ReflectionFunction
Класс ReflectionFunction позволяет
проводить реверс-инжиниринг функций.
Родительский класс ReflectionFunctionAbstract
имеет такие же методы, за исключением invoke(),
invokeArgs(), export() и
isDisabled().
Замечание:
getNumberOfParameters() и
getNumberOfRequiredParameters() были добавлены в
PHP 5.0.3, а invokeArgs() был
добавлен в PHP 5.1.0.
Для анализа функции необходимо создать экземпляр класса
ReflectionFunction.
Пример #2 Использование класса ReflectionFunction
<?php /** * Простой счетчик * * @return int */ function counter() { static $c = 0; return $c++; }
// Создание экземпляра класса ReflectionFunction $func = new ReflectionFunction('counter');
// Вывод основной информации printf( "===> Функция %s '%s'\n". " объявлена в %s\n". " строки с %d по %d\n", $func->isInternal() ? 'internal' : 'user-defined', $func->getName(), $func->getFileName(), $func->getStartLine(), $func->getEndline() );
// Вывод комментария документации printf("---> Документация:\n %s\n", var_export($func->getDocComment(), 1));
// Вывод статических переменных, если они есть if ($statics = $func->getStaticVariables()) { printf("---> Статическая переменная: %s\n", var_export($statics, 1)); }
// Вызов функции printf("---> Результат вызова: "); var_dump($func->invoke());
echo "\nReflectionFunction::export() результат:\n"; echo ReflectionFunction::export('counter'); ?>
Замечание:
Метод invoke() принимает переменное число
аргументов, которые передаются в функцию, также, как в
call_user_func().
ReflectionParameter
Класс ReflectionParameter возвращает
информацию о параметрах функции или метода.
Замечание:
getDefaultValue(),
isDefaultValueAvailable() и
isOptional() были добавлены в PHP 5.0.3,
а isArray() был добавлен в PHP 5.1.0.
getDeclaringFunction() и
getPosition() были добавлены в PHP 5.2.3.
Для анализа параметров функции необходимо создать экземпляр класса
ReflectionFunction или ReflectionMethod
и затем использовать метод getParameters() для получения
массива параметров.
Пример #3 Использование класса ReflectionParameter
<?php function foo($a, $b, $c) { } function bar(Exception $a, &$b, $c) { } function baz(ReflectionFunction $a, $b = 1, $c = null) { } function abc() { }
// Создание экземпляра класса ReflectionFunction // с параметром, заданным из командной строки. $reflect = new ReflectionFunction($argv[1]);
echo $reflect;
foreach ($reflect->getParameters() as $i => $param) { printf( "-- Параметр #%d: %s {\n". " Класс: %s\n". " Допускать NULL: %s\n". " Передан по ссылке: %s\n". " Обязательный?: %s\n". "}\n", $i, $param->getName(), var_export($param->getClass(), 1), var_export($param->allowsNull(), 1), var_export($param->isPassedByReference(), 1), $param->isOptional() ? 'да' : 'нет' ); } ?>
ReflectionClass
Класс ReflectionClass позволяет
проводить реверс-инжиниринг классов и интерфейсов.
Замечание:
hasConstant(), hasMethod(),
hasProperty(), getStaticPropertyValue()
и setStaticPropertyValue() были добавлены в PHP 5.1.0, а
newInstanceArgs() был добавлен в PHP 5.1.3.
Для анализа класса необходимо создать экземпляр класса
ReflectionClass.
Пример #4 Использование класса ReflectionClass
<?php interface Serializable { // ... }
class Object { // ... }
/** * Класс счетчик */ class Counter extends Object implements Serializable { const START = 0; private static $c = Counter::START;
/** * Вызвать счетчик * * @access public * @return int */ public function count() { return self::$c++; } }
// Создание экземпляра класса ReflectionClass $class = new ReflectionClass('Counter');
// Вывод основной информации printf( "===> %s%s%s %s '%s' [extends %s]\n" . " объявлен в %s\n" . " строки с %d по %d\n" . " имеет модификаторы %d [%s]\n", $class->isInternal() ? 'internal' : 'user-defined', $class->isAbstract() ? ' abstract' : '', $class->isFinal() ? ' final' : '', $class->isInterface() ? 'interface' : 'class', $class->getName(), var_export($class->getParentClass(), 1), $class->getFileName(), $class->getStartLine(), $class->getEndline(), $class->getModifiers(), implode(' ', Reflection::getModifierNames($class->getModifiers())) );
// Вывод комментария из документации printf("---> Документация:\n %s\n", var_export($class->getDocComment(), 1));
// Вывод тех интерфейсов, которые реализует этот класс printf("---> Интерфейсы:\n %s\n", var_export($class->getInterfaces(), 1));
// Вывод констант класса printf("---> Константы: %s\n", var_export($class->getConstants(), 1));
// Вывод свойств класса printf("---> Свойства: %s\n", var_export($class->getProperties(), 1));
// Вывод методов класса printf("---> Методы: %s\n", var_export($class->getMethods(), 1));
// Если есть возможность создать экземпляр класса, то создаем его if ($class->isInstantiable()) { $counter = $class->newInstance();
echo '---> $counter инстанцирован? '; echo $class->isInstance($counter) ? 'да' : 'нет';
echo "\n---> new Object() инстанцирован? "; echo $class->isInstance(new Object()) ? 'да' : 'нет'; } ?>
Замечание:
Метод newInstance() принимает переменное число
аргументов, которые передаются в функцию, также, как в
call_user_func().
Замечание:
$class = new ReflectionClass('Foo'); $class->isInstance($arg)
эквивалентно $arg instanceof Foo или
is_a($arg, 'Foo').
ReflectionObject
Класс ReflectionObject позволяет
проводить реверс-инжиниринг объектов.
ReflectionMethod
Класс ReflectionMethod позволяет
проводить реверс-инжиниринг методов.
Для анализа метода класса необходимо создать экземпляр класса
ReflectionMethod.
Пример #5 Использование класса ReflectionMethod
<?php class Counter { private static $c = 0;
/** * Увеличение счетчика * * @final * @static * @access public * @return int */ final public static function increment() { return ++self::$c; } }
// Создание экземпляра класса ReflectionMethod $method = new ReflectionMethod('Counter', 'increment');
// Вывод основной информации printf( "===> %s%s%s%s%s%s%s метод '%s' (which is %s)\n" . " объявлен в %s\n" . " строки с %d по %d\n" . " имеет модификаторы %d[%s]\n", $method->isInternal() ? 'internal' : 'user-defined', $method->isAbstract() ? ' abstract' : '', $method->isFinal() ? ' final' : '', $method->isPublic() ? ' public' : '', $method->isPrivate() ? ' private' : '', $method->isProtected() ? ' protected' : '', $method->isStatic() ? ' static' : '', $method->getName(), $method->isConstructor() ? 'the constructor' : 'a regular method', $method->getFileName(), $method->getStartLine(), $method->getEndline(), $method->getModifiers(), implode(' ', Reflection::getModifierNames($method->getModifiers())) );
// Вывод комментария из документации printf("---> Документация:\n %s\n", var_export($method->getDocComment(), 1));
// Вывод статических переменных, если они есть if ($statics= $method->getStaticVariables()) { printf("---> Статическая переменная: %s\n", var_export($statics, 1)); }
// Вызов метода printf("---> Результат вызова: "); var_dump($method->invoke(NULL)); ?>
Замечание:
Попытка вызова закрытого, защищенного или абстрактного метода приведет
к выбросу исключения из метода invoke().
Замечание:
При вызове статических методов нужно передать NULL в
качестве первого аргумента invoke(). Для
нестатических методов нужно передавать экземпляр класса.
ReflectionProperty
Класс ReflectionProperty позволяет
проводить реверс-инжиниринг свойств класса.
Замечание:
getDocComment() был добавлен в PHP 5.1.0.
Для анализа свойства класса необходимо создать экземпляр класса
ReflectionProperty.
Пример #6 Использование класса ReflectionProperty
<?php class String { public $length = 5; }
// Создание экземпляра класса ReflectionProperty $prop = new ReflectionProperty('String', 'length');
// Вывод основной информации о свойстве класса printf( "===> %s%s%s%s свойство '%s' (которое было %s)\n" . " имеет модификаторы %s\n", $prop->isPublic() ? ' public' : '', $prop->isPrivate() ? ' private' : '', $prop->isProtected() ? ' protected' : '', $prop->isStatic() ? ' static' : '', $prop->getName(), $prop->isDefault() ? 'объявлено во время компиляции' : 'создано во время выполнения', var_export(Reflection::getModifierNames($prop->getModifiers()), 1) );
// Создание экземпляра String $obj= new String();
// Получение текущего значения printf("---> Значение: "); var_dump($prop->getValue($obj));
// Изменение значения $prop->setValue($obj, 10); printf("---> Установка значения 10, новое значение равно: "); var_dump($prop->getValue($obj));
// Дамп объекта var_dump($obj); ?>
Замечание:
Попытка вызова закрытого или защищенного свойства класса приведет
к выбросу исключения.
ReflectionExtension
Класс ReflectionExtension позволяет
проводить реверс-инжиниринг расширений. Получить список всех загруженных
расширений можно при помощи get_loaded_extensions().
Для анализа расширения необходимо создать экземпляр класса
ReflectionExtension. Затем вы сможете вызвать
любой из методов, описанных выше.
Пример #7 Использование класса ReflectionExtension
<?php // Создание экземпляра класса ReflectionProperty $ext = new ReflectionExtension('standard');
// Вывод основной информации printf( "Имя : %s\n" . "Версия : %s\n" . "Функции : [%d] %s\n" . "Константы : [%d] %s\n" . "Директивы INI : [%d] %s\n" . "Классы : [%d] %s\n", $ext->getName(), $ext->getVersion() ? $ext->getVersion() : 'NO_VERSION', sizeof($ext->getFunctions()), var_export($ext->getFunctions(), 1),
sizeof($ext->getConstants()), var_export($ext->getConstants(), 1),
sizeof($ext->getINIEntries()), var_export($ext->getINIEntries(), 1),
sizeof($ext->getClassNames()), var_export($ext->getClassNames(), 1) ); ?>
Наследование классов Reflection
В случае, если вам требуется создать специализированные версии
встроенных классов (например, для подсветки HTML при экспорте
использовать свойства классов может быть более удобно, чем методы),
вы можете наследовать их.
Пример #8 Наследование встроенных классов
<?php /** * Свой класс Reflection_Method */ class My_Reflection_Method extends ReflectionMethod { public $visibility = array();
public function __construct($o, $m) { parent::__construct($o, $m); $this->visibility = Reflection::getModifierNames($this->getModifiers()); } }
/** * Демо-класс #1 * */ class T { protected function x() {} }
/** * Демо-класс #2 * */ class U extends T { function x() {} }
// Вывод информации var_dump(new My_Reflection_Method('U', 'x')); ?>
Замечание:
Внимание! Если вы переписываете конструктор, то не забудьте вызывать
конструктор родителя _перед_ любым кодом, который вы затем добавите.
В случае невыполнения этого условия результат будет следующим:
Fatal error: Internal error: Failed to retrieve the reflection object
|
|