Обновить
64K+

PHP *

Скриптовый язык общего назначения

60,51
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Очереди, которых нет в конфиге: динамические супервизоры Laravel Horizon

Уровень сложностиСложный
Время на прочтение34 мин
Охват и читатели5K

Очереди задач — одна из тех вещей, которые настраивают один раз и боль­ше не тро­га­ют. Кон­фиг опи­сывает извест­ные по­то­ки фоно­вых ра­бот, деп­лой раска­тывает его, вор­керы подни­мают­ся и дела­ют своё дело. Так рабо­та­ет в по­дав­ляю­щем боль­шинст­ве про­ектов. А что если появ­ляется не­об­хо­ди­мость запус­кать мак­си­маль­но изо­ли­ро­ван­ные зада­чи, ко­то­ры­ми дол­жен управ­лять поль­зо­ва­тель, а не раз­работ­чик: соз­да­вать, за­пускать, оста­нав­ли­вать? Это еди­ни­ца, ко­то­рую надо изо­ли­ро­вать, по­яв­ля­ется и исчеза­ет между деп­лоя­ми, а единст­вен­ный спо­соб рас­сказать об этом сис­теме — от­ре­дак­тиро­вать кон­фиг и рас­ка­тать всё за­ново.

В Laravel Horizon доку­мента­ция закан­чи­вает­ся на конфи­ге и паре artisan-команд про то, как поднять супер­визо­ры, наст­роить ворке­ры, их масшта­биро­вание и указать очереди. А что, если нам нуж­но соз­дать свои собст­вен­ные очере­ди и их воркеры в ран­тайме? Об этом доку­мента­ция молчит. Но если про­читать ис­ход­ни­ки, выясня­ется, что конфиг — не единст­вен­ный источ­ник исти­ны.

Эта статья на приме­ре плат­фор­мы для email-рассылок рас­скажет про пост­рое­ние дина­мичес­ких очере­дей поверх стати­чес­ко­го конфига Laravel Horizon, исполь­зуя внут­рен­ние не­до­ку­мен­ти­ро­ван­ные ме­ха­низ­мы, кото­рые Horizon сам ис­поль­зу­ет внутри себя. Про архитек­туру с авто­мати­чес­ким восс­танов­ле­нием кон­сен­су­са, раз­ре­ше­нием оши­бок и оп­ти­ми­за­цией памя­ти для дол­го жи­ву­щих оче­ре­дей.

Читать далее

Новости

Anemic vs Rich entities: нечестная дилемма

Уровень сложностиСредний
Время на прочтение9 мин
Охват и читатели4.9K

Знаменитый тезис Мартина Фаулера «Anemic Domain Model — это Antipattern» знаком многим.

Тезис простой и звучит убедительно: если модель — это просто набор геттеров и сеттеров, а бизнес-логика живёт в сервисах, то это анемичная модель, процедурный код в объектной обёртке, шаг в сторону от объектного ориентирования. Звучит так себе. Правильнее — переносить поведение внутрь объекта, рядом с данными. Заказ должен уметь рассчитывать свою сумму, добавлять предметы и применять скидку. Данные и поведение живут вместе, инкапсуляция работает, сервисы превращаются в тонкие оркестраторы. Объекты — во главе вашего дизайна.

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

Читать далее

Сколько обходится содержание одного игрока — создание своей 2D MMO RPG, ч. 22

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели9.8K

Сколько сервера уходит на одного игрока 2D MMO — вместе с существами, которых он будит вокруг себя? Показываю, как платформа считает расход живого мира ещё до установки игры: по онлайну, плотности существ и цене каждой механики, — и что из этого вышло на мире из 26 карт.

Читать далее

Как перестать писать шаблонный код в Symfony: Практические DX‑трюки для ленивого разработчика

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели8.8K

Всем привет! Меня зовут Антон Рыков и я backend-разработчик в компании "Исходный Код".

Пять CRUD-эндпоинтов. К обеду я понял: бизнес-логика заняла минут двадцать. Остальные два часа ушли на UUID вместо автоинкремента, одинаковые DTO с валидацией и ручную уборку временных файлов на стейджинге. Пальцы работали. Голова — нет.

Почти любая команда на Symfony рано или поздно упирается в ту же стену: фреймворк перестаёт быть помощником и превращается в конвейер. make:entity → вырезать integer id → прикрутить трейт дат → руками разобрать $request в контроллере. Снова. И снова.

DX — это не красивая тема в терминале. Это меньше трения между архитектурным решением и кодом. Правильная лень — точечная автоматизация того, что вы и так делаете каждый день.

В статье четыре уровня, которые убрали это трение у меня. Настроите PhpStorm так, чтобы скелет JSON-экшена появлялся по Tab. Уберёте ручной json_decode и isset через MapRequestPayload и строгие DTO. Научите MakerBundle сразу генерировать сущности с UUID и вашими трейтами. Перенесёте cron в PHP через Scheduler - расписание

Читать далее

Как я переписал каталог из 500 000 SVG‑иконок с Laravel на Go и уменьшил сервер с 4/6 ГБ до 2/2 ГБ

Время на прочтение9 мин
Охват и читатели8.5K

Больше года назад я запустил SVG4 — каталог векторных иконок. Сейчас в нём больше 500 000 SVG‑файлов.

Первая версия была написана на Laravel. На тот момент выбор был простой: Laravel я хорошо знал, на нём можно было быстро собрать рабочий проект и проверить, нужен ли он вообще кому‑нибудь.

Проект вырос. Вместе с ним выросли база, количество страниц, поисковый трафик и нагрузка. Старая версия работала на сервере с 4 ядрами и 6 ГБ оперативной памяти. После переписывания на Go весь проект работает на 2 ядрах и 2 ГБ RAM.

При этом я не ставил задачу доказать, что Go быстрее PHP. За время переписывания изменилась не только технология, но и сама архитектура приложения. Именно об этом переходе и хочу рассказать.

Читать далее

Wi-Fi из PHP: сканирование, подключение, хотспот и watchdog для Raspberry Pi без монитора и клавиатуры

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели6.5K

Библиотека для PHP, которая сканирует и подключает Wi-Fi, поднимает хотспот и держит на связи Raspberry Pi без монитора: если сеть пропала, watchdog переподключается сам, а если не выходит, поднимает точку доступа для настройки с телефона. Под капотом nmcli, wpa_cli и hostapd. Каждый релиз прогоняется на настоящем Pi, логи в репозитории.

Читать далее

Выбираем бэкенд в 2026 (PHP, Dart и C++ Drogon)

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели12K

Поехали.

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

Вторым в списке для сравнения я решил поставить Дарт. Дело в том, что самое узкое место применения Дарта — это как раз-таки применение на серверах. Потому что в мобильной разработке он уже как стандарт, веб, фронтенд мало-мальцевски он тоже подтягивает. Но вот на серверах пока что его используют очень мало. Одна из причин на то, что его мало используют на серверах, — это отсутствие библиотек, таких как, например, есть у PHP. Но, тем не менее, это совсем не значит, а тем более сейчас в эпоху LLM, это совсем не значит, что Дарт негоден на серверах. Как покажет сравнение, он очень-таки годен.

Третий кандидат для сравнения — это C++. Это его фреймворк Drogon, который в каком-то там 2014 или 2015 годах взлетел как самый быстрый фреймворк для серверов на бэкенде по скорости. Если честно, я ни разу не писал бэкенд на C++, поэтому это была первая попытка. Просто хотелось посмотреть, как C++ уничтожит двух других оппонентов со своей 100x производительностью.

Читать далее

Переезд с OpenCart 2 после двадцати лет работы: что лежит в дампе и откуда берутся восемь тысяч редиректов

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели5.4K

Разбираем переезд интернет-магазина с OpenCart 2 на Next.js и PostgreSQL. Магазин оптовый, электронные компоненты, сайту двадцать лет, в каталоге 4 751 товар. Если у вас OpenCart и вы думаете уезжать, то будет полезно почитать, что может всплыть в самый неожиданный момент.

Магазин запущен в боевом режиме, поэтому всё ниже про то, что уже перенесено и работает. Про трафик после переключения домена говорить рано, замера ещё нет. Обмен с учётной системой - отдельная большая тема, и здесь его нет.

Читать далее

SOLID в реальном мире. ISP без микроинтерфейсов

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели5K

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

Читать далее

Symfony Workflow: как реализовать сложную бизнес-логику через состояния и переходы

Время на прочтение11 мин
Охват и читатели5.8K

Заказ в интернет-магазине редко живёт по идеальной схеме «создан → оплачен → доставлен». В реальности жизненный цикл объекта нелинейный: клиент оформляет заказ, но может передумать и отменить его; товар приходит с браком и требуется возврат; часть позиций не успела прийти и нужно отправить их отдельно. Попытка реализовать такие альтернативные сценарии, проверки прав и сопутствующие действия «в лоб» быстро превращает бизнес-логику в хаос из разрозненных if/else, проверок статусов и обработчиков по всему проекту.

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

Читать далее

150 запросов на один flush, и 4343 зелёных теста. Как я делал детектор N+1 и как он сам меня обманывал

Уровень сложностиПростой
Время на прочтение15 мин
Охват и читатели4.8K

Один open‑source тайм‑трекер на Symfony имеет 4343 теста, и все они проходят. При этом каждое сохранение записи времени отправляет в базу три дополнительных SELECT запроса: ставку самой записи, ставку проекта и ставку активности. Если в одном flush() 50 записей, а столько строк показывает страница массового редактирования, только за ставками уходит 150 запросов. Тесты этот код покрывают, но ни один не падает, в них нет ни одной проверки проблем с запросами к базе данных.

Для решения этой проблемы сделал инструмент, которого в конце августа ещё не существовало. Правда, ещё до проверок сторонних проектов на N+1, он успел несколько раз обмануть меня самого, и всегда одинаково, показывал зелёное там, где на самом деле не работал.

Читать далее

Снижение нагрузки на сервер через WAF: реальный кейс WordPress/WooCommerce

Уровень сложностиСредний
Время на прочтение16 мин
Охват и читатели9.7K

Реальный кейс снижения нагрузки WordPress/WooCommerce с помощью WAF

На WordPress/WooCommerce-сайте на shared-хостинге регулярно возникали серьёзные превышения нагрузки на веб-сервер и MySQL. Штатный антибот-фильтр хостинга проблему не решил. В этом кейсе я показываю, что изменилось после подключения внешнего WAF с индивидуальной фильтрацией трафика: какие запросы создавали лишнюю нагрузку, как отсеивались парсеры, сканеры и поведенческие боты и что происходило с поисковыми роботами.

По данным Beget, после замены фильтра суточная нагрузка сайта снизилась примерно в 45 раз, базы данных — примерно в 39 раз. При этом WordPress, WooCommerce, плагины, код и структура БД не изменялись. В статье — реальные графики, данные Яндекс Метрики, статистика WAF и разбор случаев, когда WAF, наоборот, не поможет решить проблему высокой нагрузки.

Читать далее

Бесплатный плагин для входа через VK ID на WordPress: как закрыли потребность, когда готовых решений не нашлось

Время на прочтение2 мин
Охват и читатели7.7K

Начал я делать очередной сайт на Wordpress и решил упростить регистрацию пользователям. По этому пошел по схеме вход через другие сервисы. Как стало нынче модно‑сковородно использовать авторизацию через ВК. Ее то я и решил прикрутить. Делал уже это раньше но вот сегодня столкнулся с проблемой.

И есть решение

Ближайшие события

Когда разработчики ленятся писать документацию: описываем клиентский API силами нейросетей

Уровень сложностиСредний
Время на прочтение19 мин
Охват и читатели6.5K

Документация устаревает быстрее, чем код успевает писаться? Рассказываем, как мы построили конвейер из Python-скриптов и нейросетей, который сам находит изменения в PHP-контроллерах и обновляет документацию API Invapi.

Читать далее

Четыре CMS, один интерфейс публикации: WordPress, 1С-Битрикс, InSales и Joomla

Уровень сложностиСредний
Время на прочтение10 мин
Охват и читатели5.3K

Полгода назад я делал сервис, который генерирует статьи и сам кладёт их на сайт. Написать текст казалось сложной частью, а публикация — формальностью: ну дёрнем REST API, что там может быть.

Оказалось наоборот. Четыре CMS — четыре разных мира, и в каждом свой способ соврать вам об успехе.

Joomla возвращает 400, когда статья уже создана: плагин «Умный поиск» падает после записи в базу. Повторили запрос — получили дубль. InSales требует published_at даже у черновика, потому что черновиков там просто нет. А у 1С-Битрикс метода для создания статьи через API не существует вовсе — официальная документация прямо говорит про read-only режим.

Внутри: как выглядит общий интерфейс на четыре системы, почему CIBlockElement::Add() возвращает ошибку при успешно созданном элементе, зачем понадобилась двойная буферизация вывода и прямой SQL в обход автотранслитерации.

Читать далее!

Матрешка из Base64 и ROT13: разбираем вредоносный .sh, который пришел за FreePBX

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели6K

Мне в руки попался файл с расширением .sh и, конечно же, его пришлось изучить. Открываю файл — первая половина более-менее читаемая, а дальше начинается классика: Base64, ROT13 и еще немного Base64. Вроде ничего страшного. Декодируем, смотрим результат, радуемся жизни. Но не тут-то было. Автор скрипта решил сделать небольшой квест в стиле: А что если положить один скрипт внутрь другого скрипта, а потом еще один внутрь него?

Читать далее

Когда Laravel Validator становится узким местом при импорте 50 000 строк

Уровень сложностиПростой
Время на прочтение8 мин
Охват и читатели6.5K

PHP 7.4 / Laravel 8 / PostgreSQL 13

Проблема: импорт 50 тысяч строк занимал около 45 секунд.
Первое подозрение: база данных, INSERT, UPSERT, индексы, размер batch и количество запросов.
Реальность: бОльшая часть времени уходит на валидацию.

Мы начали разбираться, почему проверка нескольких десятков обычных полей на большом массиве данных оказалась значительно дороже самой записи в PostgreSQL. В итоге удалось сократить время валидации с 42,5 секунды до 0,65 секунды, а длительность всего job — примерно с 45 до 4 секунд.

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

Читать далее

Как на ровном месте сэкономить 1000+ ядер, или Куда на самом деле уходили 80% CPU

Уровень сложностиСредний
Время на прочтение18 мин
Охват и читатели16K

Всем привет, меня зовут Миша, и я бэкенд‑разработчик в платформе Яндекс Еды. Я уже рассказывал, как мы анализировали наш PHP‑монолит и вынесли из него процессинг заказов, и с тех пор роль этого легаси заметно уменьшилась. Заодно туда стали писать гораздо меньше нового кода, релизы стали реже, и он спокойненько себе работал, не привлекая лишнего внимания. 

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

Количество выделенных ядер, конечно, ещё ничего не означает, поэтому я полез смотреть реальное потребление процессорного времени, сложив CPU usage по всем подам. С помощью нехитрой арифметики я обнаружил, что 100% загрузки одного ядра приходятся на 2,5 RPS. Какое‑то время я находился в состоянии глубокого изумления, после чего решил, что это никуда не годится, и отправился в увлекательное приключение на 20 минут. 

Немного спойлеров: дело оказалось далеко не только в PHP. 

Читать далее

Пользователь придумал пароль из 100 символов. От 28 из них ваша проверка не зависит

Уровень сложностиСредний
Время на прочтение6 мин
Охват и читатели14K

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

Ломалось не у него. Так работает bcrypt, и работает уже двадцать семь лет.

Читать далее

Как записать ЛИД в Битрикс24 (заявка с сайта и подобное) через входящий вебхук на PHP

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели6.8K

Для простой серверной интеграции с Битрикс24 далеко не всегда требуется полноценная OAuth 2.0-авторизация.

Если задача — из внешнего сервиса создать контакт, проверить существующего клиента и записать лид в CRM, это можно сделать через входящий вебхук Битрикс24 и обычный PHP.

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

Читать далее
1
23 ...