Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter
10.7K subscribers
1.65K photos
27 videos
26 files
4.44K links
Все самое полезное для пхпшника в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/bca892d6

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b
Download Telegram
⚡️ Почему Redis такой быстрый

Стандартный ответ — «потому что in-memory». Это правда, но не объяснение. Куча баз данных хранит данные в памяти и не показывает таких цифр. Настоящий ответ в другом: каждое архитектурное решение Redis убирает конкретный источник latency.

🧵 Один поток

Redis обрабатывает команды последовательно в один поток. Никаких мьютексов, никакого context switching. Тысячи соединений при этом обслуживаются через epoll/kqueue — один поток следит за всеми сокетами через I/O multiplexing и не блокируется ни на одном из них.

📦 Адаптивные структуры

Hash с небольшим числом ключей хранится не как хэш-таблица, а как listpack — плотный байтовый массив, который влезает в один cache line. Никаких pointer chasing. Только когда данных становится много, Redis переключается на полноценную хэш-таблицу. Sorted Set — одновременно хэш-таблица и skiplist. O(1) по ключу и O(log N) для range-запросов без второго прохода.

💾 fork()

Снапшот RDB пишется дочерним процессом после fork(). Благодаря CoW основной процесс продолжает работу и не видит никакой паузы — ОС копирует только изменённые страницы памяти. AOF идёт дальше и логирует каждую команду, давая возможность восстановиться до последней записи. Точнее, но дороже — компромисс осознанный.

🧹 bounded expiry

Ключи с истёкшим TTL удаляются двумя способами: лениво при обращении и активно — каждые 100 мс Redis сэмплирует случайную выборку и чистит просроченные. Если таких больше 25%, повторяет цикл. Это не O(N) по всей базе, а предсказуемая нагрузка с жёстким потолком по CPU.

Redis — это не «база данных в памяти». Это система, где каждый выбор — однопоток, listpack, fork(), bounded expiry — существует потому, что альтернатива добавляла latency. In-memory здесь просто необходимое условие, а не причина скорости.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍51
⚙️ readonly свойства + clone в PHP 8.4

Классика: у тебя Value Object с readonly-свойствами, и нужно вернуть копию с одним изменённым полем. До 8.4 приходилось делать фабричный метод вручную:

class Money {
public function __construct(
public readonly int $amount,
public readonly string $currency,
) {}

public function withAmount(int $amount): static
{
return new static($amount, $this->currency);
}
}


В PHP 8.4 появился clone with:

$price = new Money(1000, 'USD');

$discounted = clone $price with {
amount: 850,
};


Никаких withField() методов на каждый чих. clone with работает даже с readonly — это единственное место, где PHP позволяет их «изменить» без рефлексии.

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8👍62🔥2👾1
🔥 Laravel Facades красота или костыль?

// Читаемо и быстро
Cache::get('user:' . $id);

// Явно и тестируемо
public function __construct(
private CacheInterface $cache,
) {}


Скрытые зависимости, нарушение SRP, привязка к фреймворку через __callStatic() — звучит страшно. Но 64% PHP-девов используют Laravel и не парятся.

Как пишете вы, Facades или DI? И считаете ли, что Тейлор красиво «продал» антипаттерн?

💬 Пишите ваше мнение в комментарии

#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5😁3🌚1
✔️ PHP-тест: Race condition

Код прошёл нагрузочное тестирование. На проде деньги задвоились 👇

📦 Задание


Фича: пользователь может переводить бонусные баллы другу. Логика простая — проверить баланс, списать, начислить. Тесты зелёные, нагрузочное прогнали — всё ок. Через три дня после релиза: у нескольких пользователей баланс ушёл в минус, у других — задвоился.

// src/Bonus/BonusTransferService.php
class BonusTransferService
{
public function __construct(
private PDO $pdo,
private BonusRepository $repo,
) {}

public function transfer(int $fromId, int $toId, int $amount): void
{
$this->pdo->beginTransaction();

try {
$fromBalance = $this->repo->getBalance($fromId);

if ($fromBalance < $amount) {
throw new InsufficientFundsException();
}

$this->repo->debit($fromId, $amount);
$this->repo->credit($toId, $amount);

$this->pdo->commit();

} catch (Throwable $e) {
$this->pdo->rollBack();
throw $e;
}
}
}

// src/Bonus/BonusRepository.php
class BonusRepository
{
public function __construct(private PDO $pdo) {}

public function getBalance(int $userId): int
{
$stmt = $this->pdo->prepare(
'SELECT balance FROM bonus_accounts WHERE user_id = ?'
);
$stmt->execute([$userId]);
return (int) $stmt->fetchColumn();
}

public function debit(int $userId, int $amount): void
{
$stmt = $this->pdo->prepare(
'UPDATE bonus_accounts SET balance = balance - ? WHERE user_id = ?'
);
$stmt->execute([$amount, $userId]);
}

public function credit(int $userId, int $amount): void
{
$stmt = $this->pdo->prepare(
'UPDATE bonus_accounts SET balance = balance + ? WHERE user_id = ?'
);
$stmt->execute([$amount, $userId]);
}
}


🔹 Задачи

— Объяснить, как именно происходит race condition в этом коде
— Почему транзакция здесь не защищает от проблемы
— Исправить getBalance так, чтобы устранить race condition

Ставьте → 🔥 если нравится формат. Если нет → 🌚

💬 Решения пишите в комменты под спойлер — сравним подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥103👍1
🤔 Разрабатываете ИИ-агентов, но всё ещё не уверены в их стабильности и прогнозируемости?

Мы поговорили с десятками разработчиков ИИ-агентов и сделали отдельный курс по AgentOps.

🧠 На нём вы узнаете:

– как оптимизировать траты на токены;
– как на практике оценить качество работы агента;
– как «докручивать» RAG-системы без потери качества;
– как обеспечить устойчивость агента к сбоям внешних сервисов без падения всей системы и про многое-многое другое.

📅 Старт: 19 мая.

👥 Спикеры — практики с опытом в AI и Data Science в крупных IT-компаниях, таких как Яндекс, Huawei, МТС и др.

Длительность: 6-12 недель в зависимости от тарифа.


🔗 Программа курса и другие подробности
🤯 Представьте, что ваш AI-агент работает так же предсказуемо, как обычный микросервис. Звучит утопически, но это именно то, к чему должна прийти разработка в 2026 году.

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

Наш обновлённый курс «Разработка AI-агентов» научит, как приручить этот хаос с помощью Python и современных фреймворков. Мы не будем учить «общаться» с нейросетью, мы будем строить из неё надёжный инструмент.

Что вы получите:


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

Есть пара мест со скидкой до завтра, решайтесь 👈🏻
🥱51
🐳 Фишка Docker CLI

Запустите docker stats с правильными флагами, и вы увидите всё в реальном времени.

🔹 Зачем это нужно


— Показывает live-метрики по CPU, памяти, сети и I/O для всех запущенных контейнеров.
— Критично для Java-сервисов: помогает поймать утечки памяти, GC pressure и неожиданный CPU spike прямо в момент нагрузки.
— Работает без установки каких-либо агентов.
— В отличие от top внутри контейнера видит реальные лимиты cgroup, а не ресурсы хоста.

🔹 Как использовать

— Все контейнеры в реальном времени: docker stats
— Конкретный сервис: docker stats my-spring-app
— Один снимок без стриминга: docker stats --no-stream
— Только нужные поля: docker stats --format "table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"
— В JSON для скриптов: docker stats --no-stream --format json

Флаг --format принимает Go-шаблоны — те же, что и в docker inspect. Можно вывести ровно то, что нужно, и скормить в jq или свой мониторинг-скрипт.

⚠️ Если контейнер запущен без -m / --memory, JVM видит всю память хоста и выставляет heap соответственно. docker stats мгновенно покажет, есть ли лимит — колонка MEM USAGE / LIMIT.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍81🔥1
🖥 Мультиагентная разработка на PHP

Пока одни продолжают спорить «нужен ли AI в разработке», другие уже автоматизируют рутину через цепочки специализированных агентов — и делают это прямо в PHP-проектах.

Свежая статья на Хабре от PHP-разработчика, который прошёл путь от «AI неудобен» до полноценного пайплайна с оркестрацией агентов в продакшене.

Что внутри:

— Почему один большой промпт не работает, и как принцип "один агент — одна ответственность" решает проблему размытия контекста
— Как выстроить цепочку: php-developer → phpstan-developer → php-test-developer → авто-фиксер — каждый в своём чистом контексте
— Specification-Driven Development на практике: спека первична, код вторичен
— Реальный опыт с Claude Code, RooCode, KiloCode — с честными плюсами и минусами

🔗 Читать на Хабре
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍1🔥1😁1🥱1
🔥 Настройка Pest PHP

Если ты всё ещё пишешь тесты на чистом PHPUnit с setUp() и простынями $this->assert... — этот пост для тебя. Настраиваем Pest с нуля в реальном Laravel-проекте.

📦 Шаг 1 — Установка

composer require pestphp/pest --dev
composer require pestphp/pest-plugin-laravel --dev
php artisan pest:install


После этого в корне появится tests/Pest.php — файл для глобальных хелперов и настроек. Не игнорируй его.

✍️ Шаг 2 — Первый тест

Забудь про классы. Pest — это функции:

it('создаёт пользователя через API', function () {
$response = $this->postJson('/api/users', [
'name' => 'Ivan',
'email' => 'ivan@example.com',
]);

$response->assertCreated();
expect($response->json('data.name'))->toBe('Ivan');
});


🧩 Шаг 3 — Datasets (параметризованные тесты)

Вместо копипасты одного теста на каждый кейс:

it('валидирует email', function (string $email) {
$response = $this->postJson('/api/users', [
'email' => $email
]);
$response->assertUnprocessable();
})->with([
'пустой' => [''],
'без собаки' => ['notanemail'],
'только домен' => ['@example.com'],
]);


⚙️ Шаг 4 — Глобальные настройки в Pest.php

Открываем tests/Pest.php и настраиваем раз и навсегда:

uses(
Tests\TestCase::class,
Illuminate\Foundation\Testing\RefreshDatabase::class,
)->in('Feature');

expect()->extend('toBeSuccess', function () {
return $this->toMatchArray([
'status' => 'success'
]);
});


Теперь RefreshDatabase не нужно писать в каждом файле, а кастомные матчеры делают тесты выразительнее.

🚀 Шаг 5 — Запуск

./vendor/bin/pest
./vendor/bin/pest --filter="создаёт пользователя"
./vendor/bin/pest --coverage # требует Xdebug или PCOV


💡 Почему Pest, а не чистый PHPUnit?

Меньше бойлерплейта, человекочитаемый вывод, встроенные архитектурные тесты (arch()) и отличная интеграция с Laravel. Команда Laravel официально рекомендует его с 11-й версии фреймворка.

Ставьте 🔥 если используете Pest.
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱11🔥61👍1😁1
🐳 Фишка Docker CLI

Контейнер запустился, но ведёт себя странно — не то сетевое окружение, не те переменные, непонятно что вообще внутри? Просто запустите docker inspect, и у вас будет полная картина без лишних инструментов.

🔹 Зачем это нужно

— Возвращает полный JSON с внутренностями: переменные окружения, тома, сетевые настройки, лимиты ресурсов, entrypoint, restart policy.
— Работает не только с контейнерами — понимает образы, тома и сети.
— Незаменимо, когда нужно быстро понять, почему контейнер ведёт себя не так, как ожидается.

🔹 Как использовать

— Полный дамп: docker inspect my-container
— Только IP-адрес: docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my-container
— Все переменные окружения: docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' my-container
— Смонтированные тома: docker inspect -f '{{json .Mounts}}' my-container | jq

Флаг -f принимает Go-шаблоны — вытащите ровно то поле, которое нужно, без парсинга тысячи строк JSON вручную.
4🔥3👍2
Исследование облачных платформ
Apple Hills Digital собирает мнения специалистов об инфраструктуре: облака, гибридные решения, on-premise.
Можно пройти короткий отбор (~3 минуты) и попасть в основную часть исследования.
Дополнительно — участие в розыгрыше iPhone*

* Принимая участие в опросе Вы становитесь участником розыгрыша под наименованием «Если ты работаешь в IT, пройди опрос и выиграй iPhone 17 Pro». Информация об организаторе розыгрыша, сроках проведения, правилах проведения розыгрыша, количестве призов, сроках, месте, порядке получения призов размещена по ссылке.
1
Какова временная сложность сортировки слиянием (Merge Sort) в худшем случае?
Anonymous Quiz
15%
O(log n)
35%
O(n^2)
10%
O(n)
40%
O(n log n)
🔥3👍1🥱1
⚡️ array_walk и внешний контекст

Многие не используют третий аргумент array_walk — а зря.

$discounts = ['vip' => 0.3, 'regular' => 0.1];
$prices = ['vip' => 1000, 'regular' => 500];

array_walk($prices, function (&$price, $key, $discounts) {
$price -= $price * ($discounts[$key] ?? 0);
}, $discounts);

// ['vip' => 700, 'regular' => 450]


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

Читается чище, зависимости явные и сразу видно, что коллбэк работает с $discounts.

🐸 Библиотека пхпшника

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
🤔 Repository в Laravel: паттерн или антипаттерн?

Eloquent — это Active Record. Когда ты оборачиваешь его в репозиторий и возвращаешь User::where(...)->get(), ты не абстрагируешься от ORM. Ты просто перекладываешь Eloquent в другой класс.

Настоящий репозиторий возвращает доменные объекты, а не модели с методами ->save() и ->delete().

💬 Что думаете?

🐸 Библиотека пхпшника

#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
👏5👍3😁1
🦾 Надоело чинить «упавших» ИИ-агентов после каждого микросбоя внешних сервисов?

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

🗓 Ждем вас 28 апреля в 19:00 МСК на эфире: «Как эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токены».

👉 Кто вещает и в чем польза?

Спикер Кирилл Кухарев (Senior AI Engineer в Raft, спикер AI Conf и Highload++). Он реализовал более 50 коммерческих проектов в GenAI и на вебинаре покажет, как взять под контроль работу нескольких агентов, чтобы они не перекидывали друг другу лишний контекст и не сжигали ваши деньги.

В прямом эфире разберем:
• Как формируется контекст в LLM при маршрутизации между агентами;
• Куда утекают лишние токены и возникает перерасход;
• Практические методы: как сжимать историю, грамотно делить задачи, лимитировать передачу контекста и собирать промпты прямо в процессе запроса пользователя.

🔥 Два способа получить максимум:

1. Приходите на вебинар 28 апреля. Дарим участникам промокод на 5.000 ₽ (работает 3 дня после эфира - это шанс забрать курс по самому низу рынка).

2. Выбирайте Инженерный трек. В подарок к нему идет полный доступ к записям и автопроверкам завершенного курса «Разработка ИИ-агентов».

👉 Занять место на вебинаре и стать профи в AgentOps
Please open Telegram to view this post
VIEW IN TELEGRAM
1😁1
💬 Обратная связь

Сколько среди нас джедаев синьоров?

Понятно, что грейд — довольно относительная история, но примерно ваш грейд:

🔥 — Senior
👍🏼 — Middle
❤️ — Junior
😁 — Ещё учусь
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥92👍79😁1917👾6