Процедурный PHP не умер
Мне пришлось немного поработать с WordPress, и я уже успел забыть все его «прелести». А главное — давно не сталкивался с процедурным подходом в рамках целого проекта.
Одно дело — небольшой мусорный скрипт, который запускается пару раз, решает конкретную задачу и отправляется в мусорку.
И совсем другое — когда так устроен целый проект.
После чистого PHP и фреймворков вроде Symfony или Laravel внутри начинается настоящая война.
Где объекты?
Где зафиксированные контракты?
Где нормальные объекты данных?
Где разделение ответственности?
Всё это где-то там, в далёком будущем. Возможно. А возможно, и нет. 🙂
И как человеку, которому интересна архитектура ПО, мне это доставляет немало неудобств.
А потом я вспомнил Go.
Язык, про который часто говорят, что там «нет нормального ООП» и невозможно построить красивую архитектуру.
Но даже там у меня получается гораздо более выразительный код и понятная структура проекта, чем в WordPress.
И тут возникает интересный вопрос: а почему WordPress вообще до сих пор такой?
Похоже, в какой-то момент ради обратной совместимости с огромным количеством плагинов и тем в жертву было принесено практически всё остальное.
Система расширения, которая когда-то была преимуществом, со временем сама стала архитектурным ограничением.
При этом полностью переписать проект и начать новую жизнь — вполне возможно. Например, OpenCart когда-то прошёл путь от 1.5.x к 2.x, фактически получив новую архитектуру.
А WordPress выбрал другой путь: сохранять совместимость и развиваться поверх существующего фундамента.
И, возможно, именно поэтому процедурный PHP в 2026 году всё ещё живёт. 🙂
Зачем я добавил Go-сервис туда, где его не просили
https://habr.com/p/1088652/
Статью таки опубликовали!
Сегодня в свободное время решил немного поработать над своим HTTP-клиентом и добавить возможность задавать конфигурацию.
Сначала я пошёл, казалось бы, очевидным путём — хотел вынести настройки в `config.json`.
Но когда начал это реализовывать, столкнулся с противоречиями.
Откуда библиотека должна брать этот файл? Зависеть от директории проекта? А где вообще эта директория в конкретном приложении? Насколько удобно пользователю каждый раз думать, где должен лежать `config.json`? А как всё это нормально поддерживать внутри Composer-пакета?
В какой-то момент пришёл к мысли, что для библиотеки такой подход вообще не нужен.
Ценность пакета как раз в том, чтобы получить готовый функционал с минимальным количеством дополнительных действий. А если после установки нужно ещё разбираться с каким-то конфигурационным файлом, который библиотека должна самостоятельно искать, то получается лишняя сложность.
Поэтому от `config.json` отказался.
Следующая идея — обычные getter и setter.
Реализовал их и уже собирался на этом остановиться, как вдруг IDE подсказала одну интересную вещь: раз пакет требует PHP 8.5, зачем вообще писать весь этот boilerplate?
Я вспомнил про `get` / `set` property hooks, которые появились в PHP 8.4.
Честно говоря, я просто забыл про эту возможность. Когда читал описание PHP 8.4, видел про property hooks, но на практике ни разу их не использовал.
В итоге вместо набора `getTimeout()`, `setTimeout()`, `getConnectTimeout()` и так далее получилась гораздо более компактная конструкция:
$config->timeout = 60;
$config->connectTimeout = 10;
При этом в `set` hook можно оставить необходимую валидацию.
Получилось красиво, минимально и, на мой взгляд, гораздо удобнее в поддержке.
Но на этом мозговой штурм не закончился.
Появилась вторая задача: я хотел, чтобы `User-Agent` всегда содержал идентификатор моего клиента. Его можно получить, но я не хочу, чтобы пользователь библиотеки мог его изменить.
И тут на помощь пришло ещё одно «чудо» из PHP 8.4 — асимметричная видимость.
В итоге можно сделать свойство публичным для чтения, но закрыть запись:
public private(set) string $userAgent = 'alf89/http-client/0.2.1';
И вот в результате обычная задача «добавить конфигурацию» привела меня сразу к двум современным возможностям PHP, которыми я раньше практически не пользовался.
В очередной раз убедился, что иногда полезно не сразу писать код, а немного остановиться и подумать: а точно ли старый привычный подход здесь лучший?
Так что `property hooks` и асимметричную видимость я точно беру себе на вооружение. Думаю, и дальше буду искать им применение там, где они действительно упрощают код.
Иногда тестовое задание не заканчивается после того, как его отправил.
В итоге продолжение этого тестового превратилось в статью на Хабре.
Разбираю, зачем вообще добавлять промежуточный сервис, почему не стал сразу тащить RabbitMQ, как подошёл к идемпотентности, очереди, retry и хранению истории.
https://habr.com/ru/sandbox/305258/
Продолжаю работу над своим HTTP-клиентом для PHP.
В новой версии 0.2.0 добавил конфигурацию HTTP-клиента: настройки `timeout`, `connectTimeout`, `User-Agent` и проверки SSL-сертификата теперь вынесены в отдельный `Config`.
Сам `CurlTransport` теперь получает конфигурацию отдельно от своей логики.
Это пока промежуточный вариант. Следующим шагом хочу вынести настройки из класса `Config` в JSON-файл, чтобы их можно было менять без редактирования исходников библиотеки.
Версия 0.2.0
https://github.com/alf07/http-client-composer/releases/tag/0.2.0
На этот раз уже не столько про код, сколько про архитектуру.
Нужно было спроектировать интеграцию 1С → Go → Yandex 360 для отправки email и сбора событий почты.
Самое интересное для меня здесь — не сама отправка письма, а то, что происходит вокруг неё: очередь, повторные попытки, падение сервиса, защита от дублей и корреляция событий между 1С, нашим сервисом и Yandex.
Например, если SMTP-запрос завершился таймаутом, нельзя просто отправить письмо ещё раз — сначала нужно понять, не было ли оно уже принято. Для этого предусмотрена дополнительная проверка Yandex.
В результате получилась архитектура, в которой состояние хранится в БД, обработка идёт асинхронно, события собираются отдельно, а падение Go-сервиса не приводит к потере очереди.
Кода не требовалось — основной упор был именно на проектирование решения.
Пожалуй, такие задания мне сейчас даже интереснее обычных CRUD.
Закончил тестовое задание на Laravel + Vue 3 и тоже добавил его на GitHub.
В проекте — авторизация, работа с организациями, парсинг данных Яндекс Карт, отзывы и рейтинг. Для тяжёлого парсинга использовал очереди, чтобы не блокировать основной запрос.
Для меня это был хороший практический проект: пришлось поработать не только с Laravel, но и с Vue, Sanctum, очередями, HTTP-запросами и разбором данных без официального API.
Возможно, позже ещё вернусь к нему и что-нибудь улучшу.
🔗 https://github.com/alf07/test-intera
Чтобы не растерять навыки в период безработицы, решил завести небольшой проект, который буду постепенно развивать.
Заодно сделать что-то полезное для себя.
Начал с HTTP-клиента для PHP — без привязки к фреймворкам, устанавливается как обычный Composer-пакет.
Пока проект небольшой, но планирую постепенно добавлять возможности, улучшать архитектуру и тестировать новые идеи.
Да и самому такой инструмент может пригодиться. 🙂
🔗
https://github.com/alf07/http-client-composer