Подключение к вызовам функций в php
Немного предыстории: Во время выполнения я хотел бы иметь возможность просматривать документацию в стиле javadoc, которая в настоящее время называется функциями, чтобы определить ее формальное (типизированное) объявление. Это позволило бы проверять типы во время выполнения (для простых и сложных типов) посредством отражения (за определенную плату) во время отладки и тестирования, что я бы счел чрезвычайно полезным.
Итак, в php я хотел бы, чтобы определяемая пользователем функция вызывалась всякий раз, когда будет вызвана любая другая функция. То есть, если вызывается функция foo(), я хотел бы, чтобы моя функция callHookHandler() вызывалась непосредственно перед этим.
Одним из решений было бы реализовать __call() во всех пользовательских классах, но это и громоздко, и не включает поддержку функций, определенных вне классов, поэтому я ищу лучшее решение.
2 answers
Это звучит немного забавно, поэтому я собираюсь попробовать ответить на него.
Я надеюсь, что это поможет вам. Дай мне знать, как все пройдет.
Итак, то, о чем вы просите, можно сделать, и вот как:
Для Функций:
- Получить все определенные функции с помощью
$function = get_defined_functions()
. - Выполните цикл по ключу
$functions['user']
и проверьте каждый из них с помощью классаReflectionFunction
. Вам нужно будет получить:- Комментарий с использованием
->getDocComment()
- Аргументы, использующие
->getParameters()
- Комментарий с использованием
- Творите чудеса (я дам вам понять, как разобрать комментарий, используя некоторые регулярные расширения, и сопоставить его со списком параметров из отражения. Не забывайте о дополнительных параметрах!)
- Переименуйте функцию, используя
runkit_function_rename
- Сгенерируйте код в строке, которая проверяет параметры и вызывает переименованную функцию
- Создайте список параметров в виде строки
- Создайте новую функцию с помощью
runkit_function_add
, используя код, сгенерированный на шаге #5 и список параметров из шага #6.
Для Занятий:
- Получить список классов с помощью
$classes = get_declared_classes();
- Просмотрите каждый из них и проверьте его с помощью
ReflectionObject
и->getMethods()
, чтобы получить методы. Убедитесь, что класс не является внутренним с помощью->isInternal()
, потому что мы ничего не можем сделать с внутренними классами. - Во внутреннем цикле... пройдите через каждый метод, используя класс
ReflectionMethod
. Получите аргументы и комментарии PHPDoc/javadoc точно так же, как вы делали с обычными функции. - Сделайте то же самое, что вы сделали с функциями, только вместо этого используйте
runkit_method_add
иrunkit_method_rename
.
Недостатки:
Вы не сможете выполнить проверку внутренних методов и функций класса (что нормально, потому что у них все равно не будет комментариев к документам).
Это большая работа! Я оставил много частей на ваше воображение, чтобы это не было длиной в короткую книгу.
Пожалуйста, пришлите мне это или откройте исходный код и дайте мне знать, когда ты заканчивай, я действительно хочу использовать это сам. Контактная информация находится на моем веб-сайте, который находится в моем профиле;)
В качестве альтернативы:
Вы можете использовать трассировку функции xdebug вместе с отражением, а затем проанализировать результаты после факта, чтобы вам не пришлось динамически редактировать код. Если вы хотите написать модульный тест, вы можете даже автоматизировать его.
Надеюсь, что проверка типов войдет в будущие версии PHP, и ждите: https://wiki.php.net/rfc/typechecking
Примечания:
Эта ссылка на класс содержит потенциально полезный пример анализа документов в разделе комментариев страница: http://us.php.net/manual/en/class.reflectionmethod.php
Ссылки
Альтернативный способ подключиться к вызову функции - использовать трюк с пространствами имен: Перехват выполнения системных функций в PHP
Вы также можете использовать Go! структура для определения аспекта, позволяющего автоматически перехватывать выполнение системных функций.