что такое рефлексия php
Введение в PHP Reflection API
Привет, Хабр! Представляю вашему вниманию перевод статьи «Introduction to PHP Reflection API» автора Mustafa Magdi.
Как в PHP анализировать структуру данных
Вступление
Когда я начал программировать на PHP, то не знал о возможностях Reflection API. Главная причина в том, что мне не нужно было проектировать свои простые классы, модули или даже пакеты. Затем я обнаружил, что это играет главную роль во многих областях. В статье мы рассмотрим Reflection API по следующим пунктам:
1. Что такое Reflection API
В информатике отражение или рефлексия (холоним интроспекции, англ. reflection) означает процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения. — Wikipedia.
Что означает возможность остановить и взглянуть внутрь своего кода (reverse-engineering )? Давайте посмотрим на следующий фрагмент кода:
Класс Profile — чёрный ящик. Используя Reflection API вы сможете прочитать, что там находится внутри:
Таким образом ReflectionClass выступает аналитиком для нашего класса Profile, и в этом состоит главная идея Reflection API.
PHP даёт вам ключ к любому запертому ящику, таким образом мы имеем ключи
для следующего:
ReflectionClass: сообщает информацию о классе.
ReflectionFunction: сообщает информацию о функции.
ReflectionParameter: извлекает информацию о параметрах функции или метода.
ReflectionClassConstant: сообщает информацию о константе класса.
Полный список вы можете изучить на php.net
2. Установка и конфигурирование
Для использования классов Reflection API нет необходимости что-либо устанавливать или настраивать, так как они входят в состав ядра PHP.
3. Примеры использования
Далее представлено несколько примеров того, как мы можем использовать Reflection API:
Пример 1:
Получить родительский класс для определённого класса:
Пример 2:
Получить документацию метода getUserName() :
Пример 3:
Может использоваться как instanceOf и is_a() для валидации объектов:
Пример 4:
В некоторых ситуациях вы можете застрять с unit-тестированием и задаться вопросом: «Как я могу протестировать закрытую функцию?!»
Не беспокойтесь, вот хитрость:
Предыдущие примеры довольно просты, но есть другие примеры, в которых вы можете увидеть, как Reflection API используется более обширно:
4. Заключение
PHP предоставляет полноценный Reflection API, который помогает легко достичь различные области ООП-структур.
5. Ссылки
Также можно посмотреть пример использования Reflection API в пакете Codeception в классе Stub.
Этот класс через рефлексию помогает мо́кать методы и свойства в unit-тестах.
Следует добавить, что Reflection API работает довольно медленно, по этому не стоит сильно увлекаться. Использовать рекомендуется в тестах или во время отладки, но если можно обойтись без него, то лучше так и сделать. И категорически не рекомендуется использовать в рабочем коде проекта, т.к. это ещё и не безопасно.
Отражние в PHP
Russian (Pусский) translation by Sergey Zhuk (you can also view the original English article)
Отражением обычно называют способность программы проверить саму себя и изменять свою логику во время выполнения. Если говорить не техническими терминами, то в отражении мы просим объект рассказать нам о своих свойствах и методах, а так же имеем возможность их изменять (включая приватные). В этом уроке, мы поглубже изучим, как это происходит, и когда этим пользоваться.
Небольшая предыстория
На заре эпохи программирования существовал языко Ассамблер. Программа, написанная на ассембре, располагается на физических регистрах внутри компьютера. Ее состав, методы и значения можно просмотреть в любое время, прочитав регистры. Даже более того, можно изменить программу, пока она выполняется, просто изменив значения этих регистров. Это требует некоторых знаний о выполняемой программе, но по своей сути отражало программу.
Как и в случае с любой крутой игрушкой, можно использовать отражение, но не злоупотреблять им.
С появлением языков высокого уровня (как например С), такие отражения стали исчезать. Затем они снова появились в объектно-ориентированных языках.
Простой пример
Отражение в PHP. В действительности может быть несколько ситуаций, когда мы можете использовать отражение, даже не подозревая об этом. Например:
Затем изменим Nettuts следующим образом:
Информация об объекте
PHP может отобразить для нас все детали объекта. Создадим PHPUnit тест для легкой и быстрой проверки нашего кода:
Теперь добавим var_dump( ) к Nettuts :
Запусти тест и увидим магию, которая происходит в выводе:
Элементы массивов, которые были получены с помощью getMethods() и getProperties() является типа данных ReflectionMethod и ReflectionProperty соответственно; эти объекты могут быть довольно полезными:
И вот наш новый вывод:
Управление данными объекта
Вызов setAccessible с параметром true сделают это:
Вот и все. Этот код меняет «John Doe» на «Mark Twain».
Непрямое использование отражения
Обратный вызов
Функция call_user_func() может принимать массив, в котором первый элемент указывает на объект, а второй на имя метода. Можно передать дополнительный параметр, который затем будет передан в вызываемый метод. Например:
Это вывод демонстрирует, что код получает следующее значение:
Использование значение переменной
Этот код выводит тоже самое, что и в предыдущем примере. PHP просто подставляет строку, которая содержится в переменной и вызывает метод. Это также работает, когда вы хотите создать объекты, используя переменные в качестве имени класса.
Когда стоит использовать отображение?
Теперь, когда мы оставили все технические детали позади, можно задаться вопросом, когда стоит использовать отображение? Вот несколько сценариев:
Заключение
Как и с любой другой крутой игрушкой, используйте отражение, но не переусердствуйте. Отражение является ценным, когда вам нужно проверить много объектов, но имеет все возможности усложнить архитектуру и дизайн вашего проекта. Я бы рекомендовал использовать его, только когда оно действительно необходимо и дает преимущество или когда никакого другого выбора уже нет.
Лично я использовал отражение лишь в нескольких сценариях, в большинстве своем при использовании сторонних модулей со слабой документацией. Я часто замечаю за собой использование кода, как в последнем примере. Легко вызывать нужный метод, когда ваш MVC отвечает с переменной, которая содержит значение «add» или «remove».
Рефлексия
Программный интерфейс Reflection API для PHP версии 5 — то же самое, что и API-интерфейс System.Reflection сборки mscorlib.dll для C#. Он состоит из встроенных классов для анализа свойств, методов и классов. В некоторых отношениях он напоминает рассмотренные в предыдущей статье функции для работы с объектами, такие как get_class_vars(), но является более гибким и позволяет учитывать больше нюансов. Он также предназначен для более эффективной работы с объектно-ориентированными средствами PHP, такими как управление доступом, интерфейсы и абстрактные классы. Старые, более ограниченные, функции классов так работать не могут.
Основные сведения
Интерфейс Reflection API можно использовать для исследования не только классов. Например, класс ReflectionFunction предоставляет информацию о заданной функции, a ReflectionExtension — информацию о скомпилированных расширениях языка PHP. В таблице ниже перечислены некоторые классы интерфейса Reflection API:
Класс | Описание |
---|---|
Reflection | Содержит статический метод export(), предоставляющий итоговую информацию о классе |
ReflectionClass | Позволяет получить информацию о классе и содержит средства для работы с ним |
ReflectionMethod | Позволяет получить информацию о методах класса и содержит средства для работы с ними |
ReflectionParameter | Позволяет получить информацию об аргументах метода |
ReflectionProperty | Позволяет получить информацию о свойствах класса |
ReflectionFunction | Позволяет получить информацию о функциях и содержит средства для работы с ними |
ReflectionExtension | Позволяет получить информацию о расширениях PHP |
ReflectionException | Предназначен для обработки ошибок |
Некоторые классы из Reflection API позволяют во время выполнения программы получить просто беспрецедентную информацию об объектах, функциях и расширениях языка, содержащихся в сценарии, которую раньше невозможно было добыть. Из-за более широких возможностей и большей эффективности, во многих случаях следует использовать интерфейс Reflection API, а не функции для работы с классами и объектами. И вскоре вы поймете, что это незаменимый инструмент для исследования классов. Например, с его помощью можно создавать диаграммы классов или документацию, сохранять информацию об объекте в базе данных, исследовать методы доступа объекта (установщики или получатели), которые используются для извлечения значений полей. Создание инфраструктуры, которая вызывает методы в классах модуля в соответствии с принятой схемой наименования — это еще один пример применения интерфейса Reflection.
Мы уже встречались с некоторыми функциями для изучения атрибутов классов. Они полезны, но обычно довольно ограниченны. А теперь давайте рассмотрим инструмент, который готов к выполнению данной работы. Класс ReflectionClass предоставляет методы, которые собирают информацию обо всех аспектах заданного класса, независимо от того, внутренний это класс или определенный пользователем. Конструктору класса ReflectionClass в качестве единственного аргумента передается имя класса, как показано ниже:
Создав объект типа ReflectionClass, вы можете использовать вспомогательный класс Reflection для создания итоговой информации о классе CDProduct. У класса Reflection есть статический метод export(), который форматирует и создает дамп данных, содержащихся в объекте типа Reflection (точнее, в любом экземпляре класса, который реализует интерфейс Reflector). Вот фрагмент вывода, полученного в результате вызова метода Reflection::export():
Исчерпывающие сведения о классе, полученные с помощью рефлексии
Как видите, метод Reflection::export() предоставляет отличный доступ к информации о классе. Этот метод дает обобщенную информацию почти о всех аспектах класса CDProduct, включая состояние доступа к свойствам и методам, аргументы, необходимые каждому методу, реализованные интерфейсы и расположение каждого метода внутри файла сценария.
Исследование класса
Метод Reflection::export() предоставляет много полезной информации для отладки, но интерфейс Reflection API можно использовать особым образом. Давайте будем работать непосредственно с классами Reflection. Вы уже знаете, как создать экземпляр объекта ReflectionClass. А теперь давайте используем объект ReflectionClass, чтобы исследовать класс CDProduct в процессе выполнения сценария. Мы хотим узнать, к какому типу класса он относится и можно ли создать его экземпляр? Вот функция, которая поможет ответить на эти вопросы:
Метод ReflectionClass::getName() возвращает имя исследуемого класса. Метод ReflectionClass::isUserDefined() возвращает истинное значение, если класс был объявлен в PHP-коде. Метод ReflectionClass::isInternal() возвращает истинное значение, если класс является встроенным. С помощью метода ReflectionClass::isAbstract() можно проверить, является ли класс абстрактным. Метод ReflectionClass::isInterface() позволяет узнать, является ли класс интерфейсом.
Определение параметров класса с помощью рефлексии
Если вы хотите создать экземпляр класса, то с помощью метода ReflectionClass::isInstantiable() можно проверить, осуществимо ли это. Можно исследовать даже исходный код класса, определенного пользователем. Объект ReflectionClass позволяет получить имя файла класса и номера первой и последней строк в этом файле, в которых этот класс определяется. Вот простой метод, в котором объект типа ReflectionClass используется для доступа к исходному коду класса:
Как видите, класс ReflectionUtil очень прост и содержит единственный статический метод ReflectionUtil::getClassSource(). Этому методу в качестве единственного аргумента передается объект типа ReflectionClass, а он возвращает исходный код класса. Метод ReflectionClass::getFileName() возвращает абсолютное имя файла класса, поэтому код должен работать без проблем и открыть данный исходный файл. Функция file() возвращает массив всех строк в файле. Метод ReflectionClass::getStartLine() возвращает номер начальной строки в исходном файле, а метод ReflectionClass::getEndLine() — номер последней строки, в которых содержится определение класса. И теперь для получения нужных строк достаточно воспользоваться функцией array_slice().
Для компактности в этом коде опущена обработка ошибок. Но в реальном приложении нужно будет проверять аргументы и коды возврата.
Определение исходного кода класса с помощью рефлексии
Исследование методов
Так же как ReflectionClass используется для исследования класса, объект типа ReflectionMethod применяется для исследования метода. Ссылку на объект ReflectionMethod можно получить двумя способами. Во-первых, можно получить массив объектов типа ReflectionMethod, вызвав метод ReflectionClass::getMethods(). А во-вторых, если вас интересует конкретный метод, то передайте его имя методу ReflectionClass::getMethod(), который и вернет соответствующий объект типа ReflectionMethod.
Ниже мы воспользуемся методом ReflectionClass::getMethods(), чтобы проверить возможности класса ReflectionMethod:
В этом коде для получения массива объектов типа ReflectionMethod используется вызов метода ReflectionClass::getMethods(). Затем в цикле выполняется обращение к каждому элементу массива и вызывается функция methodData(), которой передается полученный объект типа ReflectionMethod.
Исследование методов класса с помощью рефлексии
Имена методов, вызываемых в функции methodData(), отражают их назначение: код проверяет, является ли метод определенным пользователем, встроенным, абстрактным, общедоступным, защищенным, статическим или завершенным. Можно также проверить, является ли метод конструктором для своего класса и возвращает он ссылку или значение. Однако здесь нужно сделать одно замечание: метод ReflectionMethod::returnsReference() не возвращает истинное значение, даже если проверяемый метод возвращает объект целиком (а не ссылку на него), хотя в PHP 5 объекты передаются и присваиваются по ссылке. Этот метод возвращает истинное значение, только если исследуемый метод был явно объявлен таким, который возвращает ссылку (путем помещения символа амперсанда перед именем метода).
Исследование аргументов методов
Теперь, когда стало возможным ограничивать типы аргументов с помощью сигнатур методов, чрезвычайно полезной кажется возможность исследования аргументов, объявленных в сигнатуре метода. В интерфейсе Reflection API именно для этой цели предусмотрен класс ReflectionParameter. Чтобы получить объект типа ReflectionParameter, нам понадобится помощь объекта ReflectionMethod. Метод ReflectionMethod::getParameters() возвращает массив объектов типа ReflectionParameter.
Имея объект ReflectionParameter, можно узнать следующее: имя аргумента, была ли переменная передана по ссылке, информацию о классе, который используется для уточнения типа аргумента и будет ли метод по умолчанию назначать значение Null для аргумента.
Ниже приведен пример использования некоторых методов класса ReflectionParameter:
Код PHP Получение информации о аргументах метода-конструктора
Метод ReflectionClass::getMethod() возвращает объект типа ReflectionMethod для интересующего нас метода (в рассмотренном примере это конструктор). Затем вызывается метод ReflectionClass::getParameters() для получения массива объектов типа ReflectionParameter, соответствующих данному методу. В цикле функции argData() передается объект типа ReflectionParameter, а она возвращает информацию об аргументе.
Сначала мы узнаем имя переменной-аргумента с помощью метода ReflectionParameter::getName(). Метод ReflectionParameter::getClass() возвращает объект типа ReflectionClass, если в сигнатуре метода было использовано уточнение. Затем с помощью метода isPassedByReference() проверяется, является ли аргумент ссылкой. И, наконец, с помощью метода isDefaultValueAvailable() проверяется, было ли аргументу присвоено значение по умолчанию.
Введение в PHP Reflection API.
И это название говорит само за себя. Методы PHP Reflection API
позволяют получать информацию о классе или его экземпляре, которая не доступна другим способом.
На первый взгляд это не похоже на то, что было бы особенно полезно. Тем не менее, Reflection
на самом деле является действительно интересным аспектом разработки программного обеспечения, и
это то, что вы, вероятно, будете часто затрагивать.
Итак, в этой части мы рассмотрим Reflection API, и вот основные темы статьи:
— Что такое Reflection API.
— Установка и настройка.
— Применение.
— Вывод.
Что такое Reflection API.
Что значит возможность исследования кода? Посмотрим на фрагмент кода:
Класс Profile является черным ящиком. И если у нас нет доступа к коду, то посмотреть как
он устроен можно используя ReflectionClass:
Итак, ReflectionClass похож на аналитика для нашего класса Profile, и это основная идея Reflection API.
PHP дает ключи к закрытым параметрам, поэтому мы можем получить доступ к ним с помощью:
ReflectionClass: сообщает информацию о классе.
ReflectionFunction: сообщает информацию о функции.
ReflectionParameter: извлекает информацию о параметрах функции или метода.
ReflectionClassConstant: сообщает информацию о константе класса.
Можно посмотреть полный список на php.net.
Установка и настройка
Чтобы использовать разные классы API Reflection, нет необходимости в установке или конфигурации,
она входит в состав ядра.
Использование.
Здесь у нас есть несколько примеров того, как мы можем использовать Reflection API:
Получить родительский класс для определенного класса:
Использование в качестве аналога instanceof и is_a () для проверки объектов:
Предыдущие примеры довольно просты, вот некоторые области, в которых вы можете найти
применение Reflection API на более продвинутом уровне:
— Генератор документации: пакет laravel-apidoc-generator, он широко использует ReflectionClass & ReflectionMethod, чтобы получить информацию о блоках doc классов и методов, а затем обработать их, проверить этот блок кода.
— Контейнер для внедрения зависимостей: вот статейка на тему DI Container.
Вывод
PHP предоставляет богатый API Reflection, который облегчает жизнь в любой области ООП.
PHP Reflection это инструменты который позволяет программно заглянуть внутрь класса и получить много информации.
Приветствую!
Буду рад в любой поддержке для развития этого сайта. Номер карты Приват Банка 5169 3600 1047 4751
Класс ReflectionMethod
Введение
Класс ReflectionMethod сообщает информацию о методах.
Обзор классов
Свойства
Предопределённые константы
Модификаторы ReflectionMethod
ReflectionMethod::IS_PUBLIC
ReflectionMethod::IS_PROTECTED
ReflectionMethod::IS_PRIVATE
ReflectionMethod::IS_ABSTRACT
ReflectionMethod::IS_FINAL
Значения этих констант могут изменяться от версии к версии PHP. Рекомендуется всегда использовать константы и не полагаться напрямую на значения.
Содержание
User Contributed Notes 3 notes
We can make a «Automatic dependenci injector» in classes when her constructors depends other classes (with type hint).
class Dependence1 <
function foo () <
echo «foo» ;
>
>
class Dependence2 <
function foo2 () <
echo «foo2» ;
>
>
// Automatic dependence injection (CLASSES)
object(myClass)#6 (2) <
[«dep1″:»myClass»:private]=>
object(Dependence1)#4 (0) <
>
[«dep2″:»myClass»:private]=>
object(Dependence2)#5 (0) <
>
>
I have written a function which returns the value of a given DocComment tag.
class Example
<
/**
* This is my DocComment!
*
* @DocTag: prints Hello World!
*/
public function myMethod ()
<
echo ‘Hello World!’ ;
>
>
?>
Maybe you can add this functionality to the getDocComment methods of the reflection classes.