Всё написанное не претендует на идеологическую верность, не является рабочим примером контроллера и не рекомендуется для бездумного копирования 1 в 1.
Идею прописывать необходимые параметры передаваемые в URL прямо в аргументах функции я подглядел в Symfony2. Там же использовались комментарии PHPdoc для определения маршрутов.
Для примера, мы хотим видеть наш контроллер таким:
Итак, задача: если переменная «a» не передана, или переданы «лишние» переменные — выдается ошибка, если переменная «b» не указана, подставляется значение по умолчанию. Обе переменные проверяются по регулярным выражениям прописанным в PHPDoc.
В итоге функция проверки получилась следующая:
Пример использования:
Можно погонять различные вариации типа:
/test.php
/test.php?a=abc
/test.php?a=12
/test.php?a=12&b=another
/test.php?a=12&c=13
Можно забрать одним файлом.
Идею прописывать необходимые параметры передаваемые в 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
Можно забрать одним файлом.