Как стать автором
Обновить

Возможности PHP Reflection

Время на прочтение2 мин
Количество просмотров20K
Всё написанное не претендует на идеологическую верность, не является рабочим примером контроллера и не рекомендуется для бездумного копирования 1 в 1.

Идею прописывать необходимые параметры передаваемые в URL прямо в аргументах функции я подглядел в Symfony2. Там же использовались комментарии PHPdoc для определения маршрутов.

Для примера, мы хотим видеть наш контроллер таким:
class Controller {
    /**
     * Тестовое действие
     * @a /^[0-9]+$/i
     * @b /^[0-9a-z]+$/i
     */
    function testAction ( $a, $b = 'something' ) {
        echo 'a: '.$a.', b: '.$b;
    }
}



Если несмотря на предупреждения, вам захочется использовать пример 1 в 1, знайте:
— Reflection API работает медленно
— Невозможность обфусцирования
— Неочевидность и идеологическая кривость архитектуры
— Возможные сложности при поддержке\разработке в коллективе или сторонними разработчиками.


Итак, задача: если переменная «a» не передана, или переданы «лишние» переменные — выдается ошибка, если переменная «b» не указана, подставляется значение по умолчанию. Обе переменные проверяются по регулярным выражениям прописанным в PHPDoc.

В итоге функция проверки получилась следующая:
function CheckURLValid ( $class, $method, $values_arr = array() ) {
    $class  = new ReflectionClass( $class );
    $method = $class->getMethod( $method );
    $param  = $method->getParameters();
    $doc    = $method->getDocComment();

    //Разбираем PHPdoc
    preg_match_all( '/@([a-z0-9_-]+)([^\n]+)/is', $doc, $arr );
    $reg_arr = array_combine($arr[1], $arr[2]);

    //Проходим по аргументам функции
    $params_arr = array();
    foreach ( $param as $p ) {
        $key        = $p->getName();
        $value      = isset ( $values_arr[$key] ) ? $values_arr[$key] : false;
        $regular    = isset ( $reg_arr[$key] ) ? trim($reg_arr[$key]) : false;
        $default    = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : NULL;

        //Если есть регулярка - проверяем
        if ( isset ( $values_arr[$key] ) ) {
            if ( $regular && !preg_match( $regular, $values_arr[$key] ) )
                throw new Exception( 'Параметр "'.$key.'" указан неверно!' );

        //Если параметр обязательный и он не указан
        } elseif ( !$p->isOptional() )
            throw new Exception( 'Указаны не все обязательные параметры!' );

        //Добавляем значение в общий массив
        $params_arr[$key] = $value ? $value : $default;
    }

    //Проверяем наличие лишних параметров
    if ( count(array_diff_key( $values_arr, $params_arr )) )
        throw new Exception ( 'Указаны лишние параметры!' );

    return $params_arr;
}


Пример использования:
try {
    $arr = CheckURLValid( 'Controller', 'testAction', $_GET );
    call_user_func_array( array('Controller', 'testAction'), $arr );
} catch ( Exception $e ) {
    echo $e->getMessage();
}

Можно погонять различные вариации типа:
/test.php
/test.php?a=abc
/test.php?a=12
/test.php?a=12&b=another
/test.php?a=12&c=13

Можно забрать одним файлом.
Теги:
Хабы:
-1
Комментарии39

Публикации

Изменить настройки темы

Истории

Работа

PHP программист
155 вакансий

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн