В чем может быть проблема у простого 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")
Но когда видишь библиотеки в несколько килобайт, то вопрос чем простая регулярка плоха и чего она не учитывает? какие подводные камни могут быть? по сути маршрутизация это сердце сайт.
Дополнительно:
Фрагменты кода надо размещать в виде текста и оборачивать тэгом code для корректного отображения. Удобно делать кнопкой </>
Это обязательно, см.п.3.8 Регламента.
Сюда же относится traceback, ввод и вывод в консоли и другая структурированная текстовая инфа.
"Библиотеки на несколько килобайт" предоставляют дополнительный функционал: именованные роуты, группировки, алиасы, редиректы, middleware и т.п.
Плюс, они дают возможность писать не /catalog/(?<product>[^/]+), а /catalog/{product}.
Сам по себе простой роутер не является проблемой, если вас устраивает его функционал. Но и писать его с нуля нет никакого смысла - есть уже достаточно легковесных роутеров, которые проверены временем и которые закрывают весь основной базовый (сюда я включаю, например, middleware) функционал.
ИМХО.
Регулярка - это не магическая кнопка, которая по нажатию выдает результат. Регулярные выражения - это правила для множественных операций в отношении данных. И чем регулярка более комплексна и насыщена, тем больше будет итераций обработки входных данных.
Пример:
ОЧЕНЬ НЕ ОПТИМАЛЬНЫЙ - просто как концепция
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 ресурсов на разбор регуляркой - что бы потом выяснить что искомого роута просто нет.
- Регулярки - это не всегда медленно: https://www.npopov.com/2014/02/18/Fast-request-rou...
- Алексей Уколов, полностью согласен. Они быстры, удобны и дает хорошее покрытие.
Но это инструмент который нужно уметь использовать. Если сделать единую комплексную регулярку для обработки всех роутов - это МОЖЕТ привести к лишним операционным расходам.
Как вопрошает автор
то вопрос чем простая регулярка плоха и чего она не учитывает? какие подводные камни могут быть?
, я лишь указал на такой подводный камень. Наступит на него автор или нет покажет время.
- Да, я тоже с вами особо не спорю, просто добавил ссылку на классическую статью Никиты для контекста.
- Alex McArrow, к слову об explode: https://www.php.net/manual/ru/function.parse-url.php
- Alex McArrow,
<? $arg = "text=123&param=234&end=800"; $value = "$".str_replace("&", "; $", $arg).";"; eval ($value); echo "$text — $param — $end"; ?>
<? $arg = "text=123&param=234&end=800"; $value = "$".str_replace("&", "; $", $arg).";"; eval ($value); echo "$text — $param — $end"; ?>
Возможно не совсем безопасен, но explode free
- Сергей delphinpro, еще лучше.
Но фломастеров много и на вкус они разные.
А как я понял, автор занимается изысканиями - так что всё подойдет. - ev09, eval - совсем плохо.
"Всё что угодно, но не eval" - уж лучше пишите мега-регулярку ) - Alex McArrow, я хочу многосайтовый проект. CMS у них реализовано все, но нет гибкости. Стандартные решения от Ларавел, к каждому разделу прописывать свой роутинг не вариант. пользователи сами могут создавать разделы. Соответственно нужно динамическое решение. прописав в htaccess rewrite все прекрасно работает если файла/папки нет, то срабатывает правило, если есть то он отдается. Условно говоря index.php все обрабатывает. POST запросы add.php Но когда посмотрел то куча каких-то движков в связи с этим возник вопрос, какие могут быть траблы. Если можно тупо распарсить URL так или иначе. когда вы сделали систему, а потом выясняется, что она кривая, то все переписывать заново? всю архитектуру менять? Ну если это изыскания… не знаю как вы планируете архитектура сайт? а прокатит я 100 раз так делал?
- ev09, - многосайтовый проект - это единая система управления множествами сайтов?
а) единый роутинг + каждый сайт отдельная CMS = даже не представляю какие могут быть проблемы, но они будут и их будет много
б) единый ройтинг + каждый сайт инстанс одной CMS = всё проще, одна CMS - одна концепция роутинга.
Суть роутинга - это не просто формирования пути в адресной строки для запуска того или иного блока CMS, это "систематизация" вызова.
Пример: /catalog/tovari_dlja_doma/item/123 = /{module_name}/{slug_in_module}/{action|view}/{item_id_in_module}
Таким правилом можно закрыть 80% роутов.Нужна "систематизация" роутингов - это позволит получить гибкость в развитии модулей (их количестве и функциональности).
Но когда видишь библиотеки в несколько килобайт, то вопрос чем простая регулярка плоха и чего она не учитывает?
Вопрос сложности поддержки. Если у вас всего один паттерн для вообще всех роутов - не вопрос, юзайте регулярку.
Если же вам нужно множество паттернов роутов - тут тоже можно одной регуляркой, но ее сложность будет расти экспоненциально и проще уже будет пройтись по списку регулярок. Еще часто требуется проверять метод запроса, т.е. циклов у вас будет уже по больше. Ну конечно же желательны плюшки типа параметров например /user/{userId}/settings, но это так, к слову. Учитывая что роутер отрабатывает на каждый запрос - стоит его сделать по быстрее. Symfony роутер например компилирует все ваши роуты в микс бинарных деревьев с регулярками, не знаю есть ли другие на столько же производительные и функциональные решения.
Что касается нескольких килобайт - не парьтесь, вот вообще. Всё равно в результате будет меньше, еще и лежать в op кеше.
Ответы:
В моем htaccess есть такой код.
RewriteEngine On # Не применять к существующим файлам файлам RewriteCond %{REQUEST_FILENAME} !-f # Не применять к существующим директориям RewriteCond %{REQUEST_FILENAME} !-d # Редирект всех запросов на index.php # L означает Last, нужен чтобы на этом этапе mod_rewrite сразу остановил работу. # Короче, небольшое увеличение производительности. RewriteRule .* index.php [L] |
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) Все что больше четыре, сработает остановка.
Как-то так. А если на регулярках решать данную задачу, мне кажется это еще более нагружать сервер, да и казусы могут всякие быть.
Простите за такой длинный комментарий.
Это чисто мой велосипед и никого не призываю им пользоваться.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Проблема у простого php-роутера может быть связана с неэффективностью обработки маршрутов, неудобством в поддержке и масштабировании кода, а также отсутствием возможности использования дополнительных функций, таких как middleware или группировка маршрутов.
Одной из основных проблем может быть неэффективная обработка маршрутов. В простом php-роутере обычно используется линейный поиск маршрутов, что может привести к увеличению времени обработки запросов, особенно при большом количестве маршрутов. Решением этой проблемы может быть использование структур данных, таких как деревья маршрутов или хеш-таблицы, для быстрого поиска соответствующего маршрута.
Другой проблемой может быть неудобство в поддержке и масштабировании кода. В простом php-роутере все маршруты обычно определяются в одном файле, что может привести к его разрастанию и сложности в поддержке. Решением этой проблемы может быть разделение маршрутов на отдельные файлы с помощью роутеров высокого уровня или использование паттерна проектирования MVC для разделения логики приложения.
Также простой php-роутер может ограничивать возможности разработки, такие как middleware или группировка маршрутов. Middleware позволяет выполнять дополнительные действия перед или после обработки запроса, а группировка маршрутов упрощает организацию и поддержку кода. Решением этой проблемы может быть использование более продвинутых php-роутеров, которые поддерживают эти функции.
В итоге, проблема у простого php-роутера может быть связана с неэффективностью обработки маршрутов, неудобством в поддержке и масштабировании кода, а также отсутствием возможности использования дополнительных функций. Для решения этих проблем рекомендуется использовать более продвинутые php-роутеры, которые предоставляют больше возможностей и удобство в разработке.