Имеем таблицу маршрутизации типа такой:
array(
'board.index' => '',
'board.index.p' => 'page-{$page}.html',
'board.new' => 'boards/new.html',
// …
'topic.new' => 'boards/{$bid}/new.html',
'topic.view' => 'topics/{$tid}/',
'topic.view.p' => 'topics/{$tid}/page-{$page}.html',
// …
'search.text' => 'search.php?search=text&keywords={$text}',
'search.new' => 'search.php?action=show_recent',
'search.user' => 'search.php?action=show_user&user_id={$userid}',
);
Вероятно в таблице будет до сотни строк.
Класс Router умеет генерировать ссылки по шаблону
Router::url('topic.view.p', array('tid'=>10, 'page'=>2))
и наоборот находить маршрут для данного URL
$request = Router::request(); // "причесанный" запрос
echo 'request = "'.$request."\"\n\n";
$route = Router::route($request); // ид. маршрута или false
echo 'route = '.$route."\n\n";
if ($route !== FALSE)
{
echo "Variables:\n";
print_r(Router::getVars()); // переменные, если есть
}
Я нашел очень простой способ уменьшить число вызываемых регекспов на один запрос. Надо сравнивать входящий УРЛ с подстрокой шаблона до первой "переменной". Если постоянная часть шаблона маршрута не совпала, значит не совпадет и маршрут в-целом — незачем вызывать регексп. Таким образом, бОльшая часть сравнений делается побыстрому.
И ещё я сделал возможным маршрутизировать запросы с GET параметрами. Порядок перечисленных параметров рояля не играет, т.к. они сортируются перед сравнением.
Конечно используется кеш компилированных маршрутов.
для каждого маршрута генерится такая цепочка:
($key, $quick, $pattern, $vars) — ид. маршрута, подстрока для быстрого сравнения, шаблон регексп, имена переменных
Порядок разбора:
1. Стрижом и причесываем строку запроса. Если в запросе есть get-параметры, их порядок может измениться.
http ://mysite.ru/path/to/search.php?user_id=5&action=show_user
=>
search.php?action=show_user&user_id=5
2. Перебираем скомпилированный список маршрутов, используя простое строковое сравнение, пока не наткнемся на подходящую начальную подстроку
"search.php?action=show_user&user_id="
3. Через preg_match делаем окончательный вывод и забираем параметры
Вот чего я пока не сделал, а возможно стОит: отсортировать список маршрутов и искать быстрым поиском, например методом половинного деления. Тогда количество проверок упадет до ln(n).
Update 2010-01-21: есть версия с двоичным поиском
Архив во вложении