Канал PHP-разработчика о программировании и backend-разработке. Laravel, PHP, MySQL, Docker, Linux, Git, архитектура, производительность, GitHub, реальные проекты, задачи и ошибки, собеседования и фриланс.
SubscribersHow many subscribers the channel has now. The wave shows subscribers at each point of the period. The change is against the start of the period.8▲ 14.3 %+1 for the period
ViewsHow many views the posts published in the period have now. These are not views per day: MAX does not report how many views there were yesterday. The percentage is the change in the daily average: the current period is still running (today is not over yet), so it is compared with the previous one by pace rather than by total. “Was” is the whole previous period of the same length.21was 0
ReactionsHow many reactions the posts published in the period have. The percentage is the change in the daily average: the current period is still running (today is not over yet), so it is compared with the previous one by pace rather than by total. “Was” is the whole previous period of the same length.0was 0
MentionsHow many times other channels mentioned the channel: links and reposts, excluding advertising posts. The bigger the circle, the more mentions at that point of the period. The percentage is the change in the daily average: the current period is still running (today is not over yet), so it is compared with the previous one by pace rather than by total. “Was” is the whole previous period of the same length.61▼ 19.5 %was 76with a subscription
RepostsHow many times other channels reposted this channel's posts (excluding advertising posts). Reposts are also counted as mentions. The percentage is the change in the daily average: the current period is still running (today is not over yet), so it is compared with the previous one by pace rather than by total. “Was” is the whole previous period of the same length.28▲ 12.4 %was 25after signing in
Average post reachHow many views one post gets on average. Only posts older than two days are counted: views of fresh posts are still growing. Points with fresh posts are dashed with hollow dots: the reach of all posts right now, it will still grow.5 502▲ 0.1 %was 5 498after signing in
ERRWhat share of subscribers sees an average post: average reach ÷ subscribers × 100 %. The line shows ERR at each point of the period, the dashed line — ERR of the previous period of the same length. Points with posts younger than two days are hollow dots on the dashed end of the line.28.3 %▼ 1.2 ppdashed line — was 29.5 %after signing in
Engagement ERHow often readers react to posts: reactions ÷ views × 100 %. The tick on the bar is the previous period.2.82 %▼ 0.1 pp
Posts per dayHow many posts are published per day on average. Each cell is a point of the period: the darker, the more posts per day. The percentage is the change in the daily average: the current period is still running (today is not over yet), so it is compared with the previous one by pace rather than by total. “Was” is the whole previous period of the same length.4.1▼ 10.0 %was 4.5after signing in
Ad shareWhat share of the period's posts looks like advertising: erid labeling, ad links and other signs. The scale shows the ad load by the quality index thresholds: up to 10 % — low, up to 25 % — moderate, up to 50 % — high, above — very high. A growing share is marked red.5.7 %▲ 3.5 pp
TrendTop — subscribers at the end of each point of the period; bottom — growth per point: green means more subscribers, red means fewer. Above the growth chart — the biggest gain and the biggest loss. MAX does not report how many people subscribed and unsubscribed separately.
Audience growth
+1subscribers in the period
+1 biggest gain · 23 Oct 2026
Channel scoreA channel score from 0 to 100 made of five parts: audience, growth integrity, ad load, trust and calculation reliability. Each bar shows how many points the part earned out of its maximum. The index is recalculated every night; channels are compared with similar ones of the same category and size.
ReachHow many views the posts published at each point of the period have now (not views per day). The record is labeled; the point with today is paler — the day is not over yet. Average post reach — posts older than two days.
Views and reach
673 375views in the period▼ 9.7 %
Average post reach — 5 502 views (posts older than two days).
EngagementER — reactions divided by views, in percent — for the posts of each point of the period. The dashed line is ER for the whole period. The change is in percentage points against the previous period of the same length.
CitationsThe citation index (CI) shows how often and by which channels this channel is mentioned over the last 30 days, excluding advertising posts. The level is its place among similar channels. The line shows CI at each point of the period (for a week or month — the average over its days).
The citation index has not been calculated yet: it will appear after the nightly calculation once other channels mention the channel.
RhythmHow many posts are published on average in each hour of each weekday, Moscow time: the darker the cell, the more posts. “Best time” — the hours when posts older than two days have the highest average reach.
When and how much it posts
MonTueWedThuFriSatSun
036912151821
Best time:09:0018:00hours when posts get the highest average reach
FormatsWhat the feed is made of. Each post has one format, by priority: repost, video, photo, link, text. The bar and percentages show the share of posts of each format; on the right — average reach of one post of the format (posts older than two days), the small bar compares it with the most viewed format.
Post formats
100 posts
Reposts99 %6 168
Video2121 %7 513
Photos3838 %5 699
Links1212 %5 239
Text2020 %7 626
On the right — average reach of one post of the format.
PostsEach dot is a post in the period: horizontally — publication date, vertically — views, dot size — reactions, color — format. This shows hits, flops and how reach changes. For large channels, the 100 most viewed posts and an even sample of the rest are shown — no more than 1,500 dots.
Every post is a dot
Higher means more views, bigger means more reactions. Click a dot to open the post.
VideoPhotosOthersize — reactionsZoom with the + and − buttons, a pinch or Ctrl + mouse wheel; drag a zoomed chart to move it
SummaryTotals for the selected period: how many posts were published, how many views and reactions they have now and the average post reach. Views are the current views of posts published on those days, not views per day. The change is against the same span before the period, if statistics cover it.
Period totals
Click a metric to see it across the period below
Viewstoday — the day is not over yetPoints with posts younger than two days are pale and dashed: their views are still growing.
AdsWhat share of the period's posts looks like advertising: erid labeling, ad links and other signs. The detector is cautious, so the real share is usually higher. The scale shows the ad load by the quality index thresholds. Below — the average reach of an ad post and a regular post, and who the channel advertises (sites that ad links lead to).
What worksPosts of the period with the most views. The bar shows views relative to first place. The preview is the post's image; for a post without an image — the channel avatar. Views are the post's current count.
RhythmHow many posts were published each day of the period (pale bars) and the 7-day average (line): you can see whether the channel is speeding up or slowing down. Today is not over yet, so its average is calculated up to yesterday.
Posts by day
Pale bars are days, the line is the 7-day average: you can see whether the channel is speeding up or slowing down
Posts per day7-day average
Data updated at 21:41 Moscow time. Views are the current counts of posts published on those days; average reach counts posts older than two days.
How the quality index is calculated
Небольшое, но полезное обновление моего HTTP-клиента для PHP.
В версии 0.2.1 добавил обработку ошибок json_encode(): если данные не удаётся преобразовать в JSON, теперь выбрасывается JsonException, а не возвращается false.
Мне пришлось немного поработать с WordPress, и я уже успел забыть все его «прелести». А главное — давно не сталкивался с процедурным подходом в рамках целого проекта. Одно дело — небольшой мусорный скрипт, который запускается пару раз, решает конкретную задачу и отправляется в мусорку. И совсем другое — когда так устроен целый проект. После чистого PHP и фреймворков вроде Symfony или Laravel внутри начинается настоящая война. Где объекты? Где зафиксированные контракты? Где нормальные объекты данных? Где разделение ответственности? Всё это где-то там, в далёком будущем. Возможно. А возможно, и нет. 🙂 И как человеку, которому интересна архитектура ПО, мне это доставляет немало неудобств. А потом я вспомнил Go. Язык, про который часто говорят, что там «нет нормального ООП» и невозможно построить красивую архитектуру. Но даже там у меня получается гораздо более выразительный код и понятная структура проекта, чем в WordPress. И тут возникает интересный вопрос: а почему WordPress вообще до сих пор такой? Похоже, в какой-то момент ради обратной совместимости с огромным количеством плагинов и тем в жертву было принесено практически всё остальное. Система расширения, которая когда-то была преимуществом, со временем сама стала архитектурным ограничением. При этом полностью переписать проект и начать новую жизнь — вполне возможно. Например, OpenCart когда-то прошёл путь от 1.5.x к 2.x, фактически получив новую архитектуру. А WordPress выбрал другой путь: сохранять совместимость и развиваться поверх существующего фундамента. И, возможно, именно поэтому процедурный PHP в 2026 году всё ещё живёт. 🙂
Сегодня в свободное время решил немного поработать над своим 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()` и так далее получилась гораздо более компактная конструкция:
При этом в `set` hook можно оставить необходимую валидацию.
Получилось красиво, минимально и, на мой взгляд, гораздо удобнее в поддержке.
Но на этом мозговой штурм не закончился.
Появилась вторая задача: я хотел, чтобы `User-Agent` всегда содержал идентификатор моего клиента. Его можно получить, но я не хочу, чтобы пользователь библиотеки мог его изменить.
И тут на помощь пришло ещё одно «чудо» из PHP 8.4 — асимметричная видимость.
В итоге можно сделать свойство публичным для чтения, но закрыть запись:
public private(set) string $userAgent = 'alf89/http-client/0.2.1';
И вот в результате обычная задача «добавить конфигурацию» привела меня сразу к двум современным возможностям PHP, которыми я раньше практически не пользовался.
В очередной раз убедился, что иногда полезно не сразу писать код, а немного остановиться и подумать: а точно ли старый привычный подход здесь лучший?
Так что `property hooks` и асимметричную видимость я точно беру себе на вооружение. Думаю, и дальше буду искать им применение там, где они действительно упрощают код.
Иногда тестовое задание не заканчивается после того, как его отправил.
В итоге продолжение этого тестового превратилось в статью на Хабре.
Разбираю, зачем вообще добавлять промежуточный сервис, почему не стал сразу тащить RabbitMQ, как подошёл к идемпотентности, очереди, retry и хранению истории.
В новой версии 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.
Возможно, позже ещё вернусь к нему и что-нибудь улучшу.
Necessary cookies keep the site working and secure: sign-in, form protection, language, theme and others. Yandex Metrica analytics cookies and Yandex Advertising Network ad cookies are enabled only with your consent. By clicking “Accept all” you give consent to processing of cookie data; see the Personal Data Processing Policy for details.