@ev09

В чем может быть проблема у простого php-роутера?

По сути имея URL можно свести к
www.site.ru/catalog/subcatalog/file.html?key=value
т.е. можно разобрать регуляркой на составные части и потом на основе прописанных настроек все собирать
если сайт такой-то, а catalog/subcatalog/ такой-то то берем такой-то шаблон, если есть file.html то это конечная страница, если нет, то это список, обрабатываем key value и вызывем функцию ($site, "catalog/subcatalog/ ", $file=NULL, "key=value")
или($site, "catalog/subcatalog/ ", "telephone-iphone-15-black", "key=value")
Но когда видишь библиотеки в несколько килобайт, то вопрос чем простая регулярка плоха и чего она не учитывает? какие подводные камни могут быть? по сути маршрутизация это сердце сайт.
  • Вопрос задан
  • 140 просмотров
Решения вопроса 3
alexey-m-ukolov
@alexey-m-ukolov Куратор тега PHP
"Библиотеки на несколько килобайт" предоставляют дополнительный функционал: именованные роуты, группировки, алиасы, редиректы, middleware и т.п.
Плюс, они дают возможность писать не /catalog/(?<product>[^/]+), а /catalog/{product}.

Сам по себе простой роутер не является проблемой, если вас устраивает его функционал. Но и писать его с нуля нет никакого смысла - есть уже достаточно легковесных роутеров, которые проверены временем и которые закрывают весь основной базовый (сюда я включаю, например, middleware) функционал.
Ответ написан
Комментировать
AlexMcArrow
@AlexMcArrow
Люблю РНР, да я такой!
ИМХО.
Регулярка - это не магическая кнопка, которая по нажатию выдает результат. Регулярные выражения - это правила для множественных операций в отношении данных. И чем регулярка более комплексна и насыщена, тем больше будет итераций обработки входных данных.
Пример:
ОЧЕНЬ НЕ ОПТИМАЛЬНЫЙ - просто как концепция
www.site.ru/catalog/subcatalog/file.html?key=value&key2=value2
Если использовать explode, то сперва разбиваем по / - получаем
  • www.site.ru
  • catalog
  • subcatalog
  • file.html?key=value&key2=value2

Далее для "последнего" элемента применяем еще один explode по ?
  • www.site.ru
  • catalog
  • subcatalog
    • file.html
    • key=value&key2=value2



Далее для "последнего" элемента применяем еще один explode по & - что бы обработать возможное множество переданных GET-параметров
  • www.site.ru
  • catalog
  • subcatalog
    • file.html
      • key=value
      • key2=value2




И теперь для всего множества GET-параметров, explode по =
  • www.site.ru
  • catalog
  • subcatalog
    • file.html
        • key
        • value

        • key2
        • value2







И на весь этот ужас мы потратим: 3 explode + (explode * на кол-во GET-параметров) и при этом можем вложить проверки на необходимость выполнения следующих шагов не только по содержимому данных, но и по вхождению в "базе роутов" = если мы понимаем что catalog не существует => зачем пытаться разбирать дальше, если и так уже ни чего не найдем и можно сразу бросать Exception для перехода на 404.

А вот итерационные операции регулярного выражения могут (с большей вероятностью) иметь больше операций.

Вывод:
Чем сложнее регулярка тем "дороже" ее исполнение.
И как вы верно сделали утверждение, роутер это основа которая должна работать быстро. А вы можете потратить много CPU ресурсов на разбор регуляркой - что бы потом выяснить что искомого роута просто нет.
Ответ написан
index0h
@index0h
PHP, Golang. https://github.com/index0h
Но когда видишь библиотеки в несколько килобайт, то вопрос чем простая регулярка плоха и чего она не учитывает?

Вопрос сложности поддержки. Если у вас всего один паттерн для вообще всех роутов - не вопрос, юзайте регулярку.
Если же вам нужно множество паттернов роутов - тут тоже можно одной регуляркой, но ее сложность будет расти экспоненциально и проще уже будет пройтись по списку регулярок. Еще часто требуется проверять метод запроса, т.е. циклов у вас будет уже по больше. Ну конечно же желательны плюшки типа параметров например /user/{userId}/settings, но это так, к слову. Учитывая что роутер отрабатывает на каждый запрос - стоит его сделать по быстрее. Symfony роутер например компилирует все ваши роуты в микс бинарных деревьев с регулярками, не знаю есть ли другие на столько же производительные и функциональные решения.

Что касается нескольких килобайт - не парьтесь, вот вообще. Всё равно в результате будет меньше, еще и лежать в op кеше.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@grek_cheburek
Программист самоучка
В моем htaccess есть такой код.

RewriteEngine On
# Не применять к существующим файлам файлам
RewriteCond %{REQUEST_FILENAME} !-f
# Не применять к существующим директориям
RewriteCond %{REQUEST_FILENAME} !-d
# Редирект всех запросов на index.php
# L означает Last, нужен чтобы на этом этапе mod_rewrite сразу остановил работу.
# Короче, небольшое увеличение производительности.
RewriteRule .* index.php [L]


Далее, в моем роуторе я обращаюсь через $_SERVER['REQUEST_URI']
Разбиваю его на части.
К примеру у меня есть два адреса.
site.ru/blog/one-day
site.ru/de/blog/one-day
Все что разделено косыми чертами, я отдал на откуп explode.
Роутору объяснил, что нулевой может иметь два значения и он это должен учитывать. Если в нем храниться только две буквы и не более, тогда он должен привести нас в изменение языка интерфейса. Если букв больше, тогда он должен привести нас в модуль, который мы хотим вызвать.
Если модуля нет, тогда нужно отправить пользователя на 404, но в моем случае я отправляю пользователя на главную.
Причем я делаю проверку не только на существование каталога для модуля, но и на существование некоторых файлов.
А $_GET параметры передаются автоматически и их не нужно обрабатывать.
site.ru/blog/one-day?page=comments&sort=desc
$_GET параметры сами подставятся как положено и их не нужно прогонять через роутер.
Аааа, простите, забыл добавить, что у меня есть второй explode, который в самом начале разделяет строку через знак ?

Мой файл имеет размер в 3.2 kb и 48 строк.
Но это только лишь из-за развернутых комментариев, которые я писал для себя, чтобы не запутаться.
Да, в таком роуторе должен быть метод, который пошлет куда подальше пользователя, если он будет безобразно вводить адрес сайта.
К примеру, у вас есть материал по адресу
site.ru/blog/one-day, но после one-day ничего нет, то тут должна сработать защита, которая просто прогонит пользователя на главную или подготовленную страницу для таких случаев.
Я реализовал это таким способом.
Есть метод error404(), который принимает номер элемента, после которого должна произойти остановка.
site.ru/blog/one-day
Только два элемента и третьего нет, тогда я вызываю метод error404(2) и все что будет введено после one-day, сработает остановка.
site.ru/blog/one-day/photo/city-berlin
error404(4) Все что больше четыре, сработает остановка.

Как-то так. А если на регулярках решать данную задачу, мне кажется это еще более нагружать сервер, да и казусы могут всякие быть.

Простите за такой длинный комментарий.
Это чисто мой велосипед и никого не призываю им пользоваться.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы