Классы и объекты (PHP 5)
PHP Manual

Reflection

Содержание

Введение

В PHP 5 имеется полный набор Reflection API, который предоставляет возможность проводить реверс-инжиниринг классов, интерфейсов, функций, методов, а также расширений. В дополнение к этому, Reflection API предоставляет средства для извлечения комментариев для функций, классов и методов.

Reflection API - это объектно-ориентированное расширение для Zend Engine, состоящее из следующих классов:

<?php
class Reflection { }
interface 
Reflector { }
class 
ReflectionException extends Exception { }
class 
ReflectionFunction extends ReflectionFunctionAbstract implements Reflector { }
class 
ReflectionParameter implements Reflector { }
class 
ReflectionMethod extends ReflectionFunctionAbstract implements Reflector { }
class 
ReflectionClass implements Reflector { }
class 
ReflectionObject extends ReflectionClass { }
class 
ReflectionProperty implements Reflector { }
class 
ReflectionExtension implements Reflector { }
?>

Замечание: Более подробно эти классы рассматриваются в следующих главах.

Пример #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.

<?php
interface Reflector
{
    public 
string __toString()
    public static 
string export()
}
?>

ReflectionException

ReflectionException наследует стандартный класс Exception и выбрасывается Reflection API, он не реализует никаких специальных методов или свойств.

ReflectionFunction

Класс ReflectionFunction позволяет проводить реверс-инжиниринг функций.

<?php
class ReflectionFunction extends ReflectionFunctionAbstract implements Reflector
{
    final private 
__clone()
    public 
void __construct(string name)
    public 
string __toString()
    public static 
string export(string namebool return)
    public 
string getName()
    public 
bool isInternal()
    public 
bool isDisabled()
    public 
bool isUserDefined()
    public 
string getFileName()
    public 
int getStartLine()
    public 
int getEndLine()
    public 
string getDocComment()
    public array 
getStaticVariables()
    public 
mixed invoke([mixed args [, ...]])
    public 
mixed invokeArgs(array args)
    public 
bool returnsReference()
    public 
ReflectionParameter[] getParameters()
    public 
int getNumberOfParameters()
    public 
int getNumberOfRequiredParameters()
}
?>

Родительский класс 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($statics1));
}

// Вызов функции
printf("---> Результат вызова: ");
var_dump($func->invoke());


echo 
"\nReflectionFunction::export() результат:\n";
echo 
ReflectionFunction::export('counter');
?>

Замечание: Метод invoke() принимает переменное число аргументов, которые передаются в функцию, также, как в call_user_func().

ReflectionParameter

Класс ReflectionParameter возвращает информацию о параметрах функции или метода.

<?php
class ReflectionParameter implements Reflector
{
    final private 
__clone()
    public 
void __construct(string function, string parameter)
    public 
string __toString()
    public static 
string export(mixed function, mixed parameterbool return)
    public 
string getName()
    public 
bool isPassedByReference()
    public 
ReflectionClass getDeclaringClass()
    public 
ReflectionClass getClass()
    public 
bool isArray()
    public 
bool allowsNull()
    public 
bool isPassedByReference()
    public 
bool isOptional()
    public 
bool isDefaultValueAvailable()
    public 
mixed getDefaultValue()
}
?>

Замечание: 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 позволяет проводить реверс-инжиниринг классов и интерфейсов.

<?php
class ReflectionClass implements Reflector
{
    final private 
__clone()
    public 
void __construct(string name)
    public 
string __toString()
    public static 
string export(mixed class, bool return)
    public 
string getName()
    public 
bool isInternal()
    public 
bool isUserDefined()
    public 
bool isInstantiable()
    public 
bool hasConstant(string name)
    public 
bool hasMethod(string name)
    public 
bool hasProperty(string name)
    public 
string getFileName()
    public 
int getStartLine()
    public 
int getEndLine()
    public 
string getDocComment()
    public 
ReflectionMethod getConstructor()
    public 
ReflectionMethod getMethod(string name)
    public 
ReflectionMethod[] getMethods()
    public 
ReflectionProperty getProperty(string name)
    public 
ReflectionProperty[] getProperties()
    public array 
getConstants()
    public 
mixed getConstant(string name)
    public 
ReflectionClass[] getInterfaces()
    public 
bool isInterface()
    public 
bool isAbstract()
    public 
bool isFinal()
    public 
int getModifiers()
    public 
bool isInstance(stdclass object)
    public 
stdclass newInstance(mixed args)
    public 
stdclass newInstanceArgs(array args)
    public 
ReflectionClass getParentClass()
    public 
bool isSubclassOf(ReflectionClass class)
    public array 
getStaticProperties()
    public 
mixed getStaticPropertyValue(string name [, mixed default])
    public 
void setStaticPropertyValue(string namemixed value)
    public array 
getDefaultProperties()
    public 
bool isIterateable()
    public 
bool implementsInterface(string name)
    public 
ReflectionExtension getExtension()
    public 
string getExtensionName()
}
?>

Замечание: 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 позволяет проводить реверс-инжиниринг объектов.

<?php
class ReflectionObject extends ReflectionClass
{
    final private 
__clone()
    public 
void __construct(mixed object)
    public 
string __toString()
    public static 
string export(mixed objectbool return)
}
?>

ReflectionMethod

Класс ReflectionMethod позволяет проводить реверс-инжиниринг методов.

<?php
class ReflectionMethod extends ReflectionFunctionAbstract implements Reflector
{
    public 
void __construct(mixed class, string name)
    public 
string __toString()
    public static 
string export(mixed class, string namebool return)
    public 
mixed invoke(stdclass object [, mixed args [, ...]])
    public 
mixed invokeArgs(stdclass object, array args)
    public 
bool isFinal()
    public 
bool isAbstract()
    public 
bool isPublic()
    public 
bool isPrivate()
    public 
bool isProtected()
    public 
bool isStatic()
    public 
bool isConstructor()
    public 
bool isDestructor()
    public 
int getModifiers()
    public 
ReflectionClass getDeclaringClass()

    
// Унаследовано из ReflectionFunctionAbstract
    
final private __clone()
    public 
string getName()
    public 
bool isInternal()
    public 
bool isUserDefined()
    public 
string getFileName()
    public 
int getStartLine()
    public 
int getEndLine()
    public 
string getDocComment()
    public array 
getStaticVariables()
    public 
bool returnsReference()
    public 
ReflectionParameter[] getParameters()
    public 
int getNumberOfParameters()
    public 
int getNumberOfRequiredParameters()
}
?>

Для анализа метода класса необходимо создать экземпляр класса 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($statics1));
}

// Вызов метода
printf("---> Результат вызова: ");
var_dump($method->invoke(NULL));
?>

Замечание: Попытка вызова закрытого, защищенного или абстрактного метода приведет к выбросу исключения из метода invoke().

Замечание: При вызове статических методов нужно передать NULL в качестве первого аргумента invoke(). Для нестатических методов нужно передавать экземпляр класса.

ReflectionProperty

Класс ReflectionProperty позволяет проводить реверс-инжиниринг свойств класса.

<?php
class ReflectionProperty implements Reflector
{
    final private 
__clone()
    public 
void __construct(mixed class, string name)
    public 
string __toString()
    public static 
string export(mixed class, string namebool return)
    public 
string getName()
    public 
bool isPublic()
    public 
bool isPrivate()
    public 
bool isProtected()
    public 
bool isStatic()
    public 
bool isDefault()
    public 
int getModifiers()
    public 
mixed getValue(stdclass object)
    public 
void setValue(stdclass objectmixed value)
    public 
ReflectionClass getDeclaringClass()
    public 
string getDocComment()
}
?>

Замечание: 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($obj10);
printf("---> Установка значения 10, новое значение равно: ");
var_dump($prop->getValue($obj));

// Дамп объекта
var_dump($obj);
?>

Замечание: Попытка вызова закрытого или защищенного свойства класса приведет к выбросу исключения.

ReflectionExtension

Класс ReflectionExtension позволяет проводить реверс-инжиниринг расширений. Получить список всех загруженных расширений можно при помощи get_loaded_extensions().

<?php
class ReflectionExtension implements Reflector {
    final private 
__clone()
    public 
void __construct(string name)
    public 
string __toString()
    public static 
string export(string namebool return)
    public 
string getName()
    public 
string getVersion()
    public 
ReflectionFunction[] getFunctions()
    public array 
getConstants()
    public array 
getINIEntries()
    public 
ReflectionClass[] getClasses()
    public array 
getClassNames()
    public 
string info()
}
?>

Для анализа расширения необходимо создать экземпляр класса 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 {
    protected function 
x() {}
}

/**
 * Демо-класс #2
 *
 */
class extends {
    function 
x() {}
}

// Вывод информации
var_dump(new My_Reflection_Method('U''x'));
?>

Замечание: Внимание! Если вы переписываете конструктор, то не забудьте вызывать конструктор родителя _перед_ любым кодом, который вы затем добавите. В случае невыполнения этого условия результат будет следующим: Fatal error: Internal error: Failed to retrieve the reflection object


Классы и объекты (PHP 5)
PHP Manual