index php page thread

Простой вариант реализации многопоточности на PHP

Многопоточность в PHP отсутствует «из коробки», поэтому вариантов её реализации было придумано великое множество, включая расширения pthreads, AzaThread (CThread), и даже несколько собственных наработок PHP программистов.

Основным минусом для меня стало слишком больше количество «наворотов» у этих решений — не всегда есть необходимость в обмене информации между потоками и родительским процессом или в экономии ресурсов. Всегда должна быть возможность быстро и с минимумом затрат решить задачу.

Заранее хочу оговориться, что в этом посте не открываются великие тайны — он скорее для новичков в языке, и опубликовать его я решил только потому, что в свое время сам столкнулся с проблемой и не найдя готового решения сделал эдакую эмуляцию многопоточности самостоятельно.

Итак, задача состоит в том, что бы обработать большое количество данных, пришедших в наш скрипт. Моей задачей было обработать JSON массив текстовой информации, переварив которую скрипт должен был собрать из неё не менее большой коммит для PostgreSQL.

Первым делом собираем данные в родительском файле:

Размер массива колебался около 400мб (позже сократился до

50мб), и вся информация была текстовой. Не сложно прикинуть скорость, с которой это всё переваривалось, а если учесть, что скрипт выполнялся по cron каждые 15 минут, а вычислительная мощность была такой себе — быстродействие страдало очень сильно.

После получения данных можно прикинуть их объем и при необходимости рассчитать необходимое количество потоков на каждое ядро ЦП, а можно просто решить, что потоков будет 4 и посчитать количество строк для каждого потока:

Стоит сразу оговориться — такой расчет «в лоб» не даст точного результата по количеству элементов для каждого потока. Он нужен скорее для упрощения расчетов.

А теперь самая суть — создаем задачи для каждого потока и запускаем его. Делать мы это будем «в лоб» — создавая задачу для второго файла — thread.php. Он будет выступать в роли «потока», получая диапазон элементов для обработки и запускаясь независимо от основного скрипта:

Функция passthru() используется для запуска консольных команд, но скрипт будет ждать окончания выполнения каждой из них. Для этого мы оборачиваем команду на запуск в набор операторов, которые запустят процесс и тут же вернут ничего, запустив процесс и родительский процесс не приостановится в ожидании выполнения каждого дочернего:

Что конкретно тут происходит, к сожалению, точно сказать не могу — набор параметров мне подсказал мой знакомый линуксоид. Если в комментах сможете расшифровать эту магию — буду признателен и дополню пост.

Вот таким, довольно простым, способом можно реализовать эмуляцию многопоточности в PHP.

Если сократить весь пример до сухого вывода, то думаю он звучал бы так: родительский поток через командную строку запускает дочерние процессы, указывая им какую именно информацию обработать.

Говоря «эмуляцию» я имею в виду, что при таком методе реализации нет возможности для обмена информацией между потоками или между родительским и дочерними потоками. Он подходит в случае, если заранее известно, что такие возможности не нужны.

Источник

PHP Profi

Квест → Как хакнуть форму

Многопоточность в PHP с помощью Pthreads Перевод

Похоже, PHP разработчики редко используют параллельность. Говорить о простоте синхронного кода не буду, однопоточное программирование, конечно, проще и понятнее, но иногда небольшое использование параллельности может принести ощутимое повышение производительности.

В этой статье мы взглянем на то, как многопоточность может быть достигнута в PHP с помощью расширения pthreads. Для этого потребуется установленная ZTS (Zend Thread Safety) версия PHP 7.x, вместе с установленным расширением pthreads v3. (На момент написания статьи, в PHP 7.1 пользователям нужно будет установить из ветки master в репозитории pthreads – см. подробнее как установить (en) стороннее расширение.)

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

Большое спасибо Joe Watkins (создателю расширения pthreads) за вычитку и помощь в улучшении моей статьи!

Когда не стоит использовать pthreads

Прежде чем мы начнём, я хотел бы уточнить, когда вы не должны (да и не можете) использовать расширение pthreads.

В pthreads v2, рекомендация была в том, что pthreads не должна использоваться в веб-серверной среде (т.е. в fcgi процессе). Что касается pthreads v3, эта рекомендация является программным ограничением, так что теперь вы просто не сможете использовать его в среде веб-сервера. Две известные причины:

Вот почему многопоточность не является хорошим решением в такой среде. Если вы рассматриваете многопоточность как решение задач, блокирующих ввод-вывод (например, выполнение http-запросов), то позвольте мне обратить ваше внимание на асинхронное программирование, которое можно реализовать с помощью фреймворков, таких как Amp.

После такого отступления, давайте сразу перейдём к делу!

Обработка разовых задач

Давайте взглянем на иерархию классов, предлагаемую расширением pthreads:

Переиспользование потоков

Вот небольшой пример:

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

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

pthreads и (не)изменяемость

Давайте взглянем на пример, который продемонстрирует новые ограничения неизменяемости:

Давайте снова взглянем на пример, чтобы лучше понимать некоторые вещи:

В качестве демонстрации:

Синхронизация

В последнем разделе этой статьи мы рассмотрим синхронизацию в pthreads. Синхронизация — это метод, позволяющий контролировать доступ к общим ресурсам.

Для примера, давайте реализуем простейший счетчик:

Без использования синхронизации, вывод не детерминирован. Несколько потоков пишут в одну переменную без контролируемого доступа, что означает что обновления будут потеряны.

Синхронизированные блоки кода могут также взаимодействовать друг с другом, используя методы Threaded::wait и Threaded::notify (или Threaded::notifyAll ).

Вот поочерёдный инкремент в двух синхронизированных циклах while:

Заключение

Если вам интересен перевод следующего поста, дайте знать: комментируйте в соц. сетях, плюсуйте и делитесь постом с коллегами и друзьями.

Источник

Многопоточные вычисления в PHP: pthreads

Недавно я попробовал pthreads и был приятно удивлен — это расширение, которое добавляет в PHP возможность работать с несколькими самыми настоящими потоками. Никакой эмуляции, никакой магии, никаких фейков — все по-настоящему.

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

Я рассматриваю такую задачу. Есть пул заданий, которые надо побыстрее выполнить. В PHP есть и другие инструменты для решения этой задачи, тут они не упоминаются, статья именно про pthreads.

Стоит отметить, что автор расширения, Joe Watkins, в своих статьях предупреждает, что многопоточность — это всегда не просто и надо быть к этому готовым.

Кто не испугался, идем далее.

Что такое pthreads

Pthreads — это объектно-ориентированное API, которое дает удобный способ для организации многопоточных вычислений в PHP. API включает в себя все инструменты, необходимые для создания многопоточных приложений. PHP-приложения могут создавать, читать, писать, исполнять и синхронизировать потоки с помощью объектов классов Threads, Workers и Threaded.

Что внутри pthreads

Иерархия основных классов, которые мы только что упомянули, представлена на диаграмме.
index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

Threaded — основа pthreads, дает возможность параллельного запуска кода. Предоставляет методы для синхронизации и другие полезные методы.

Thread. Можно создать поток, отнаследовавшись от Thread и реализовав метод run(). Метод run() начинает выполняться, причем в отдельном потоке, в момент, когда вызывается метод start(). Это можно инициировать только из контекста, который создает поток. Объединить потоки можно тоже только в этом-же контексте.

Worker. Персистентное состояние, которое в большинстве случаев используется разными потоками. Доступно, пока объект находится в области видимости или до принудительного вызова shutdown().

Помимо этих классов есть еще класс Pool. Pool — пул (контейнер) Worker-ов можно использовать для распределения Threaded объектов по Worker-ам. Pool — наиболее простой и эффективный способ организовать несколько потоков.

Не будем сильно грустить над теорией, а сразу попробуем все это на примере.

Пример

Можно решать разные задачи в несколько потоков. Мне было интересно решить одну конкретную и как мне кажется весьма типовую задачу. Напомню ее еще раз. Есть пул заданий, их надо побыстрее выполнить.

Так давайте приступим. Для этого создадим провайдер данных MyDataProvider (Threaded), он будет один и общий для всех потоков.

Для каждого потока у нас будет MyWorker (Worker), где будет храниться ссылка на провайдер.

Сама обработка каждой задачи пула, (пусть это будет некая ресурсоемкая операция), наше узкое горлышко, ради которого мы и затеяли многопоточность, будет в MyWork (Threaded).

Получается довольно элегантно на мой взгляд. Этот пример я выложил на гитхаб.

Вот и все! Ну почти все. На самом деле есть то, что может огорчить пытливого читателя. Все это не работает на стандартном PHP, скомпилированным с опциями по умолчанию. Чтобы насладиться многопоточностью, надо, чтобы в вашем PHP был включен ZTS (Zend Thread Safety).

Настройка PHP

После этого можно ставить расширение pthreads.

Вот теперь все. Ну… почти все. Представьте, что вы написали мультипоточный код, а PHP на машине у коллеги не настроен соответствующим образом? Конфуз, не правда ли? Но выход есть.

pthreads-polyfill

Тут снова спасибо Joe Watkins за пакет pthreads-polyfill. Суть решения такова: в этом пакете содержатся те-же классы, что и в расширении pthreads, они позволяют выполниться вашему коду, даже если не установлено расширение pthreads. Просто код будет выполнен в один поток.
Чтобы это заработало, вы просто подключаете через composer этот пакет и больше ни о чем не думаете. Там происходит проверка, установлено ли расширение. Если расширение установлено, то на этом работа polyfill заканчивается. Иначе подключаются классы-”заглушки”, чтобы код работал хотя бы в 1 поток.

Проверим

Информация о процессоре, на котором запускал тесты

Посмотрим диаграмму загрузки ядер процессора. Тут все соответствует ожиданиям.

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

А теперь самое главное, ради чего все это. Сравним время выполнения.

$threadsПримечаниеВремя выполнения, секунд
PHP без ZTS
1без pthreads, без polyfill265.05
1polyfill298.26
PHP с ZTS
1без pthreads, без polyfill37.65
168.58
226.18
316.87
412.96
512.57
612.07
711.78
811.62

Из первых двух строк видно, что при использовании polyfill мы потеряли примерно 13% производительности в этом примере, это относительно линейного кода на совсем простом PHP “без всего”.

Далее, PHP с ZTS. Не обращайте внимание на такую большую разницу во времени выполнения в сравнении с PHP без ZTS (37.65 против 265.05 секунд), я не пытался привести к общему знаменателю настройки PHP. В случае без ZTS у меня включен XDebug например.

Как видно, при использовании 2-х потоков скорость выполнения программы примерно в 1.5 раза выше, чем в случае с линейным кодом. При использовании 4-х потоков — в 3 раза.

Можно обратить внимание, что хоть процессор и 8-ядерный, время выполнения программы почти не менялось, если использовалось более 4 потоков. Похоже, это связано с тем, что физических ядра у моего процессора 4. Для наглядности изобразил табличку в виде диаграммы.

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

Резюме

В PHP возможна вполне элегантная работа с многопоточностью с использованием расширения pthreads. Это дает ощутимый прирост производительности.

Источник

Прогресс выполнения тяжелой задачи в PHP

Случилось мне как-то иметь дело с тяжелым PHP-скриптом. Нужно было каким-то образом в браузере отображать прогресс выполнения задачи в то время, пока в достаточно длительном цикле на стороне PHP проводились расчёты. В таких случаях обычно прибегают к периодичному выводу строки вроде этой:

Этот вариант меня не устраивал по нескольким причинам, к тому же мне в принципе не нравится такой подход.

Итераций у меня было порядка 3000—5000. Я прикинул, что великоват трафик для такой несложной затеи. Кроме того, мне такой вариант казался очень некрасивым с технической точки зрения, а внешний вид страницы и вовсе получался уродлив: футер дойдет еще не скоро — после последнего уведомления о 100% выполнении задачи.

Увернуться от проблемы некрасивой страницы большого труда не составляло, но остальные минусы заставили меня обрадоваться и приступить к поискам более изящного решения.

Решение простое. Основанная страница — это пульт управления. С пульта можно запустить и остановить задачу. Эта страница инициирует XMLHttpRequest — стартует выполнение основной задачи. В процессе выполнения этой задачи (внутри основного цикла) скрипт отправляет клиенту один байт — символ пробела. На пульте в обработчике onreadystatechange мы, получая байт за байтом, сможем делать вывод о прогрессе выполнения задачи.

Схема такая. Скрипт операции:

Однако, итераций всего 50. Об этом мы знаем, потому что сами определили их количество в файле скрипта. А если не знаем или количество может меняться? При readyState == 2 мы можем получить информацию из заголовков. Давайте этим и воспользуемся для определения количества итераций:

А на пульте получим и запомним это значение:

Общая схема должна быть ясна. Поговорим теперь о подводных камнях.

Кроме того, то ли Nginx, то ли FastCGI, то ли сам Chrome считают, что инициировать прием-передачу тела ответа, которое содержит всего-навсего один байт — слишком расточительно. Поэтому нужно предварить всю операцию дополнительными байтами. Нужно договориться, скажем, что первые 20 пробелов вообще ничего не должны означать. На стороне PHP их нужно просто «выплюнуть» в вывод, а в обработчике onreadystatechange их нужно проигнорировать. На мой взгляд — раз уж вся конфигурационная составляющая передается в заголовках — то и это число игнорируемых пробелов тоже лучше передать в заголовке. Назовем это padding-ом.

На стороне клиента это тоже нужно учесть:

Откуда число 20? Если подскажете — буду весьма признателен. Я его установил экспериментальным путем.

С ее помощью можно обойти все уровни буферизации, вывести данные напрямую, после чего все буферы восстанавливаются.

Кстати, а почему именно пробел используется для уведомления о выполненной части задачи? Просто потому что почти любой формат представления данных в вебе такими пробелами не испортишь. Можно применить такой метод передачи уведомления о прогрессе операции, а после всего этого вывести отчет о результатах в JSON.

Если все привести в порядок, немного оптимизировать и дополнить код всеми возможностями, которые могут пригодиться, получится вот что:

Источник

Маршрутизация во фреймворках: Управление адресами URL

index php page thread. Смотреть фото index php page thread. Смотреть картинку index php page thread. Картинка про index php page thread. Фото index php page thread

Каждый разработчик, знакомящийся с каким-либо фреймворком, проходит некий путь знакомства с системой маршрутизации запросов в нём. Данный компонент присутствует во многих системах и служит для использования «красивых» адресов страниц. В этой статье мы познакомимся с работой этой системы.

Генерация адресов ссылок

Кто-то наверняка не желая разобраться в этой теме сразу жёстко прописывает во всех представлениях адреса со вставками:

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

Но через некоторое время всё-таки переписывает все ссылки на использование системного метода createUrl :

Попробуем понять эволюцию мыслей разработчика сайта на фреймворке.

Первым делом, прочуствуем сильные стороны автоматизации обработки URL адресов. Давайте разработаем крупную и гибкую систему и автоматизируем в ней абсолютно всё, что попадается под руку.

Управление адресами страниц в приложении

Давным давно, в стране первых веб-программистов PHP файлы произвели революцию в разработке сайтов. Ведь тогда каждый ремесленник мог построить мега-портал с использованием GET параметров, которые он передавал из форм и ссылок на свой сервер.

Он мог динамически выводить страницы:

товары в своём магазине:

редкие записи в своём блоге:

Потом программист задумался о модульности. И подумал, что было бы неплохо взять только файл index.php (который, кстати, вписывать в адресную строку необязательно) и пускать все запросы через него:

и в конфигурации Nginx:

а регулярные выражения переместить в конфигурационные файлы приложения и ту же работу производить вручную в PHP скрипте. Кроме того, удобно разместить правила преобразования адресов в модулях, например правила для блога поместить в соответствующий файл modules/blog/routes.php :

Пишем своё приложение

Попробуем использовать этот подход в небольшом приложении.

Пусть у нас методы-действия для вывода ленты записей блога названы с префиксом action_ и собраны в виде функций в файле-контроллере list.php :

а действия для просмотра (а также, при желании, создания и редактирования) записи – в файле-контроллере post.php :

Аналогично мы можем создать модуль магазина shop с файлами-контроллерами catalog, product, cart, order с соответствующими функциями-действиями внутри.

Добавим настройки к нашему приложению:

И соберём наш парсер адресов в файле index.php :

То есть, если мы теперь зайдём по адресу

Модернизируем наш парсер дальше.

Передача параметров в маршрут

Ссылка кнопки удаления товара из корзины могла бы выглядеть так:

Конечно же, мы могли бы добавить значение номера товара в шаблон адреса:

и указывать номер прямо в пути

но это было бы слишком педантично и малополезно. Так что оставим первый вариант.

Опыт работы с регулярными выражениями может подсказать нам сократить несколько конкретных правил до одного универсального.

Будь у нас такая же возможность, мы могли бы заменить список похожих правил:

всего одной строкой:

Но, к сожалению, функция preg_replace поддерживает обращение к фрагментам только по порядковому номеру, например:

Устраним этот недостаток, а именно воспользуемся функцией str_replace :

Здесь мы операцией

заменяем подстановки на их значения.

Теперь при переходе по адресу

Теперь мы можем совершить чудо. Просто добавим в конец списка тройку правил:

Это будут запасные правила по умолчанию, позволяющие вызывать любое действие любого контроллера. С ними у нас заработает любой модуль, у которого нет своих правил.

Фактически, парсинг адресов на основе регулярных выражений у нас готов.

Достоинства обработки адресов в программном коде

Как мы упоминали, первая причина кроется в облегчении поддержки модульности. Разумнее хранить правила прямо в модуле и подключать к приложению динамически. Иначе бы приходилось каждый раз при подключении нового функционала вручную или в скрипте-установщике дописывать правила в файл ‘.htaccess`. А если используется не Apache, а иной сервер, то ручная правка неизбежна.

Если с этим доводом можно поспорить и нет ничего страшного в правке файлов, то другая причина развевает все сомнения. Эта причина – возможность обратного конструирования адресов на основе маршрутов.

Генерация адресов из маршрутов

Например, если у нас есть правило

то при заходе по адресу

у нас должен произойти разбор адреса и выполниться действие rss контроллера list модуля blog. Одновременно если мы напишем в шаблоне строку

должно произойти обратное преобразование, то есть результирующий HTML-код страницы должен содержать строку

Аналогично вызов функции create_url с дополнительными параметрами

должен найти подходящий шаблон

И в третьем случае

должно найтись совпадение с правилом

и сгенерироваться корректный адрес:

Как выход из данной ситуации можно придумать свой облегчённый язык, реализующий только некоторые необходимые функции, и сделать анализатор конкретно для него.

Первым делом, вместо неудобных конструкций (?P \d+) было бы приятнее использовать облегчённые

Теперь при разборе адреса можно простой заменой строки реализовать преобразование псевдошаблона в настоящее регулярное выражение.

Упрощение анализа шаблонов

Вторая сложность при парсинге регулярных выражений заключается в поддержке необязательных параметров. Например, вместо указания страницы как GET параметр

для поддержки ЧПУ для страниц

Аналогично мы могли бы добавить другие параметры. В парсере такого выражения нам бы пришлось разбираться во множестве скобок.

Это сложный синтаксис, но вовсе не обязательный. Вместо него мы можем использовать несколько простых для анализатора правил:

При наличии параметра page в аргументах функции при вызове create_url сработает первое правило. Иначе случится совпадение со вторым.

Введя свой микроязык можно отойти от настоящего синтаксиса регулярных выражений, упростить его и даже добавить свои идеи. Но это нам пока не нужно.

Теперь рассмотрим такое правило

Здесь в произвольном месте вне именованного параметра id добавлена группа (html|xml|json) для возможности принимать расширение (что может понадобиться для работы сайта по Ajax), но эта группа никак не названа.

При попытке открыть адрес http://site.com/blog/post/52.xml это правило вполне себе сработает, но попытка создать адрес по нему

ни к чему ни приведёт, так как наш анализатор не будет знать, какое расширение нужно указать после точки.

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

. Другими словами, обеспечить, чтобы абсолютно все параметры были именованными.

В связи с этим данный шаблон должен выглядеть так:

и вызываться он должен с передачей значений всех имеющихся параметров

По этой же причине мы не можем указать необязательность параметра на нашем псевдоязыке вот так:

так как теперь мы знаем, что скобки не окажут должного эффекта. Система их примет за обычные символы и при генерации просто выведет как есть:

Так что если нужно сделать указание расширения необязательным, то создайте два правила:

При передаче идентификатора и расширения сработает первое, а только для идентификатора – второе.

Можно использовать и запасной работоспособный вариант:

Мы здесь намеренно разрешили использование регулярных выражений только для значений именованных параметров. Это привело к невозможности использовать их для самой строки шаблона, но защитило нас от создания негенерируемых правил и позволило значительно упростило анализ.

Теперь не составит труда выделить из шаблона все упоминаемые в нём параметры одним простым проходом функции preg_match_all или сгенерировать на основе шаблона настоящее регулярное выражение. Генерировать адрес по такому шаблону тоже достаточно легко.

Теперь мы можем продолжить исследование и перейти от процедурного подхода к объектно-ориентированному.

Объектно-ориентированная реализация маршрутизатора

Попробуем сейчас построить каркас, в который мы можем инкапсулировать наш код.

Первым делом, создадим сущность для оформления правила. Дополним для большего удобства наш класс некоторыми свойствами:

Теперь добавим в наше приложение менеджер адресов, который будет хранить список правил и обходить их при поиске нужного:

В самом приложении мы теперь можем использовать наш менеджер:

А в представлениях и контроллерах для построения ссылок использовать метод createUrl :

Обратите внимание, что в классе UrlRule много доступных для настройки опций. Специально для этого мы сделали наш менеджер таким, что он может получать не только пары

но и конфигурируемые записи с любым числом опций:

Свои классы правил маршрутизации

Порой указания простого маршрута не хватает для корректной работы приложения. Это может происходить при конфликтах нескольких похожих адресов.

Пусть, например, у нас статические страницы:

Оно будет срабатывать в последнюю очередь (если предшествующие ему правила не сработают). Но предположим, что у нас есть и стандартный правила, упоминаемые ранее. Если мы поместим наше правило после стандартного:

то при попытке открыть страницу

Если мы поставим правило для статических страниц выше стандартного:

то при заходе по адресу

тоже сработает первое правило, и вместо действия shop/default/index откроется страница shop, которой тоже не существует.

Это неудивительно, так как правила проверяются по списку сверху вниз, и если будет несколько подходящих правил, то выбор остановится на первом из них.

Обычного правила из простой пары шаблон-маршрут недостаточно для работы такого вывода страниц. Во избежание такой путаницы шаблон должен быть «умным», а именно должен проверять наличие страницы и срабатывать только тогда, когда страница существует.

Теперь добавим наше правило с указанием класса:

Вспомним, что наш менеджер производит перебор правил из своего массива rules по очереди:

а наш умный класс сам в методе createUrl генерирует адрес в нужном формате. Также в действии контроллера этот идентификатор благодаря коду

Что мы узнали

в нужном правиле или глобально для всего менеджера (реализовать такую глобальную опцию в классе UrlManager достаточно легко: добавить открытое свойство в класс UrlManager и брать его значение как значение по умолчанию внутри UrlRule), и адреса мгновенно поменяются. Это очень удобно.

Также мы теперь знаем, что в шаблонах правил разные системы маршрутизации могут применять либо «ненастоящий» язык регулярных выражений, то есть свой собственный упрощённый аналог, либо позволяют использовать регулярные выражения только в специфических местах. Поэтому не стоит удивляться, что некоторые символы в правилах разных маршрутизаторов не сработают и будут выведены как простой текст.

В следующей части мы с вами рассмотрим реализацию маршрутизации в Yii.

Не пропускайте новые статьи, бонусы и мастер-классы:

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *