URL/URI Router

Всем хорошего настроения! Данная статья поможет понять что такое роутер. Сразу скажу: она НЕ рассчитана для новичков, как и большинство материалов данного ресурса. Если вы имеете опыт программирования на PHP и хотите до конца разобраться что же такое роутер и какое отношение он имеет к ЧПУ — эта статья для Вас! Мы с вами создадим элементарнейшую реализацию. В конце статьи выложу исходники для скачивания и тестирования. Потом обсудим недостатки и несколько серьезных готовых решений.

Что же такое роутеры, для чего они нужны, как пользоваться и какой выбрать? Чтобы ответить на эти вопросы, для начала необходимо ознакомиться с понятием «ЧПУ». В этом нам поможет (статья на Wikipedia).

Прочли? Итак, сделали с помощью mod_rewrite и .htaccess «переадресацию» всех несуществующих «файлов» и «папок» на наш index.php. Именно НЕ существующих! Обратите на это особое внимание! И вот теперь нам нужен инструмент, который, собственно говоря, и вызовет нужную функцию или метод (смотря какой подход вы используете при программировании). Можно пойти совершенно банальнейшим способом. Допустим, имеем адрес example.com/catalogue/showitems/10. Приведу пример для ООП, поскольку непоколебимо убежден в тесной связи между ЧПУ и ООП. Это во-первых. Во-вторых: большинство современных фреймворков (Yii, Kohana, CodeIgnitor, CakePHP, Zend и т.д.) используют именно объектно-ориентированный подход, как и большинство готовых роутеров. Так что говорить о процедурке смысла не вижу. Но не будем отвлекаться. Имеем следующее:

http://example.com/catalogue/showitems/10
example.com — домен.
catalogue — класс
showitem — метод
10 — некий параметр, который мы передаем методу.

Создаем папку, например, controllers и пишем в ней файл примерно такого содержания:

//File controllers/catalogue.php
class catalogue
{
    public function defaultmethod()
    {
        /*Так выводить иноформацию не рекомендуется. Чисто пример. */
        echo "Thi is default method of the catalogue class";
    }
 
    public function showitem($id)
    {
        echo "This is showitem method of the catalogue class!";
        print_r($id);
    }
}

Обратите внимание, имя файла должно соответствовать имени класса. Это общепринятый стандарт, не будем вдаваться в подробности — чуть позже из кода поймете почему так нужно. Теперь как нам вызвать метод showitem? Внимательно прочитали статью на википедии? =) Для этого у нас есть .htaccess и mod_rewrite. Наш запрос (http://example.com/catalogue/showitems/10) «переадресовался» на index.php. А там мы можем в простейшем случае сворганить что-то вроде такого парсера/роутера:

//File idex.php
 
$classname = 'defaultclass'; //Имя класса по умолчанию
$method = 'defaultmethod';   //Метод по умолчанию
$arg = array();              //Массив с аргументами
 
$controllerspath = $_SERVER['DOCUMENT_ROOT'].'/controllers'; //Устаавливаем папку с контроллерами
 
$parsed = parse_url($_SERVER['REQUEST_URI']); //Парсим URL
 
$url = trim(urldecode($parsed['path']), '/'); //Декодируем и убираем лишние слэши.
$elements = explode('/', $url);
$count = count($elements);
 
if($count > 2)
{
    $classname=$elements[0];
    $method=$elements[1];
    for($i=2; $i<$count; $i++)
    {
        $arg[]=$elements[$i];
    }
}
elseif($count == 2)
{
    $classname=$elements[0];
    $method=$elements[1];
}
elseif($count == 1 and $elements[0] != NULL)
{
    $classname=$elements[0];
}
 
require_once("$controllerspath/$classname.php");
$obj = new $classname;
call_user_func(array($obj, $method), $arg);

Вот и всё! Какие недостатки? Их, на самом деле, великое множество…
1. Хотим URL вида example.com/article/2 — не получится. Нужен формат «домен/контроллер/метод/id»
2. Конкретно данная реализация упрощена до невозможности и нет обработки исключений. Вызовем не существующий класс и получим ошибку. Тоже самое с методом.
3. Нет маршрутизации по регулярным выражениям. Нет возможности тонкой маршрутизации
4. Не учитывается REST модель.

Ну и хватит, пожалуй. Хотя недостатков, конечно, больше… Но в принце, для каких-то внутренних проектов вполне неплохое решение. Скажем, корпоративный web ресурс для внутреннего использования в сегменте SOHO!

Поэтому теперь, когда мы разобрались что такое URL роутер и можем представить примерно схему его работы, предлагаю посмотреть в сторону AltoRouter. На сегодняшний день мой любимый URL router.