fa
Feedback
Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter

Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter

رفتن به کانال در Telegram

Все самое полезное для пхпшника в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/bca892d6 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b

نمایش بیشتر

📈 تحلیل کانال تلگرام Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter

کانال Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter (@phpproglib) در بخش زبانی روسی بازیگری فعال است. در حال حاضر جامعه شامل 10 712 مشترک است و جایگاه 11 598 را در دسته فناوری و برنامه‌ها و رتبه 61 274 را در منطقه روسيا دارد.

📊 شاخص‌های مخاطب و پویایی

از زمان ایجاد در невідомо، پروژه رشد سریعی داشته و 10 712 مشترک جذب کرده است.

بر اساس آخرین داده‌ها در تاریخ 05 ژوئن, 2026، کانال فعالیت پایداری دارد. در ۳۰ روز گذشته تغییر اعضا برابر -34 و در ۲۴ ساعت گذشته برابر -1 بوده و همچنان دسترسی گسترده‌ای حفظ شده است.

  • وضعیت تأیید: تأیید نشده
  • نرخ تعامل (ER): میانگین تعامل مخاطب 15.28% است و در ۲۴ ساعت نخست پس از انتشار، محتوا معمولاً 9.13% واکنش نسبت به کل مشترکان کسب می‌کند.
  • دسترسی پست‌ها: هر پست به طور میانگین 1 637 بازدید دریافت می‌کند. در اولین روز معمولاً 978 بازدید جمع‌آوری می‌شود.
  • واکنش‌ها و تعامل: مخاطبان به‌طور فعال حمایت می‌کنند؛ میانگین واکنش به هر پست 11 است.
  • علایق موضوعی: محتوا بر موضوعات کلیدی مانند php, laravel, пхпшника, artisan, api تمرکز دارد.

📝 توضیح و سیاست محتوایی

نویسنده این فضا را محل بیان دیدگاه‌های شخصی توصیف می‌کند:
Все самое полезное для пхпшника в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/bca892d6 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b

به لطف به‌روزرسانی‌های پرتکرار (آخرین داده در تاریخ 06 ژوئن, 2026)، کانال همواره به‌روز و دارای دسترسی بالاست. تحلیل‌ها نشان می‌دهد مخاطبان به‌طور فعال با محتوا تعامل دارند و آن را به نقطه اثرگذاری مهم در دسته فناوری و برنامه‌ها تبدیل کرده‌اند.

10 712
مشترکین
-124 ساعت
-97 روز
-3430 روز
آرشیو پست ها
⚙️ 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

Локализация текстов в Symfony: от статических переводов к динамическим данным из базы. Бесплатный урок курса «Symfony Framewo
Локализация текстов в Symfony: от статических переводов к динамическим данным из базы. Бесплатный урок курса «Symfony Framework» Перевести интерфейс через файлы — это только начало. Настоящие сложности начинаются тогда, когда переводить нужно не статичные строки, а содержимое из базы данных, которое живёт в административной панели, меняется редакторами и должно оставаться управляемым с точки зрения архитектуры. 📅 На открытом уроке 15 апреля в 20:00: — Разберём реальный сценарий локализации в Symfony — от стандартного подхода со статическими переводами до более сложной работы с динамическими текстами из базы данных. — Покажем возможности компонента symfony/translation, разберём подходы к хранению переводов, варианты моделей данных и практическую реализацию получения локализованного содержимого через Doctrine.
Урок не для тех, кто хочет решить многоязычность «одной таблицей на всё», не думает о поддержке архитектуры и считает, что локализация заканчивается на переводе кнопок и заголовков.
👉 Записаться: https://clc.to/x9D9Pg Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

⚡️ Почему 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 здесь просто необходимое условие, а не причина скорости.

#байтовый_юмор
#байтовый_юмор

🧭 Разбираем современный PHP вместе с Podlodka PHP Crew PHP-стек может устаревать незаметно: решения вроде бы работают, но ск
🧭 Разбираем современный PHP вместе с Podlodka PHP Crew PHP-стек может устаревать незаметно: решения вроде бы работают, но скорость разработки снижается, стоимость поддержки растёт, а количество возможностей сокращается. 💡 Эксперты Podlodka PHP Crew собрали онлайн-конференцию «Современный стек PHP-разработки», чтобы разобраться, как всё устроено сегодня. 🗓С 20 по 24 апреля участники: • изучат, как сегодня запускают PHP-приложения (worker mode, новые рантаймы, FrankenPHP), • посмотрят, как изменилась инфраструктура и что пора выкинуть из Docker-стека, • обсудят, как реально применять AI-агентов в разработке (не только писать код, но и расследовать баги и планировать изменения), • разберут практические кейсы (например, в онлайн-режиме будут запускать мультиплеерную игру на PHP с Temporal и RoadRunner), • и в целом поймут, какие инструменты и подходы действительно стоит внедрять в 2026. Формат — пять дней живых Zoom-сессий по утрам и вечерам, закрытое комьюнити в Telegram и общение со спикерами. Если хотите обновить свой стек и лучше понимать, куда движется разработка на PHP — обязательно присоединяйтесь👇 🎟Early-bird билеты доступны до 13 апреля А по промокоду php_crew_8_1wcIhz получите скидку🎁

Какой признак характерен для архитектуры CQRS?
Anonymous voting

📊 Doctrine vs Eloquent Их сравнивают как два способа работать с БД. На самом деле это два разных взгляда на то, что такое доменная модель. Eloquent — Active Record. Модель знает о базе данных. Она сама сохраняет себя, сама удаляет, сама строит запросы. Это удобно и это цена: бизнес-логика и слой персистентности перемешаны с рождения.
// Eloquent — модель и есть запись в таблице
$user = User::where('email', $email)->firstOrFail();
$user->status = 'active';
$user->save();
Doctrine — Data Mapper. Модель ничего не знает о БД. EntityManager знает, как сохранить объект. Объект остаётся чистым PHP-классом.
// Doctrine — модель не знает про persist
$user = $this->repository->findByEmail($email);
$user->activate(); // метод в домене, не save()
$this->em->flush();
✔️ Где Eloquent выигрывает — CRUD-приложения, где домен тонкий — Быстрый старт, меньше конфигурации — Команда знакома с Laravel — не надо учить новый mental model Где Eloquent начинает мешать — Сложные агрегаты с инвариантами — Хочешь тестировать доменную логику без БД — Один объект — несколько таблиц или наоборот ✔️ Где Doctrine оправдан — Богатая доменная модель (DDD, агрегаты, value objects) — Нужна полная изоляция домена от инфраструктуры — Сложные маппинги, наследование, polymorphic relations с контролем Главный сигнал: если ты ловишь себя на том, что пишешь методы в Eloquent-модели, которые делают $this->save() — домен начинает протекать. Это не баг Eloquent, это его дизайн. Просто решай осознанно. 🐸 Библиотека пхпшника #элементарный_выбор

🔒 Prepared statements Prepared statements защищают от инъекций. Но также их можно осознанно использовать для оптимизации. Когда вы выполняете один и тот же запрос в цикле — БД каждый раз парсит и строит план выполнения заново. Плохо:
foreach ($userIds as $id) {
    $pdo->query("SELECT * FROM users WHERE id = $id"); // парсинг + план на каждой итерации
}
Хорошо — prepare один раз, execute много раз:
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
 
foreach ($userIds as $id) {
    $stmt->execute([':id' => $id]);
    $user = $stmt->fetch();
}
БД кеширует план выполнения запроса\. На 10 000 итераций разница ощутима\. Ещё лучше — batch-запрос:
$placeholders = implode(',', array_fill(0, count($userIds), '?'));
$stmt = $pdo->prepare("SELECT * FROM users WHERE id IN ($placeholders)");
$stmt->execute($userIds);
$users = $stmt->fetchAll();
// Один запрос вместо N
Библиотека пхпшника #vardump

#байтовый_юмор
#байтовый_юмор

✔️ PHP-тест: Generators + Memory leak + Batch-обработка «Мы перешли на генераторы, чтобы не грузить память» — но память всё равно растёт 👇 📦 Задание Команда переписала импорт CSV на генераторы — раньше падало с OOM на файлах больше 500 МБ. После рефакторинга память перестала расти... на стейджинге. На проде с реальными файлами на 2M+ строк потребление всё равно ползёт вверх.
// src/Import/CsvImporter.php
class CsvImporter
{
    private array $processedIds = [];
    private array $errors       = [];
    private int   $totalRows    = 0;

    public function import(string $filePath): ImportResult
    {
        foreach ($this->readRows($filePath) as $row) {
            $this->totalRows++;

            try {
                $id = $this->processRow($row);
                $this->processedIds[] = $id;
            } catch (RowException $e) {
                $this->errors[] = [
                    'row'     => $this->totalRows,
                    'message' => $e->getMessage(),
                    'data'    => $row,
                ];
            }
        }

        return new ImportResult($this->processedIds, $this->errors, $this->totalRows);
    }

    private function readRows(string $filePath): \Generator
    {
        $handle = fopen($filePath, 'r');
        $headers = fgetcsv($handle);

        while (($raw = fgetcsv($handle)) !== false) {
            yield array_combine($headers, $raw);
        }

        fclose($handle);
    }

    private function processRow(array $row): int
    {
        // Валидация, маппинг, вставка в БД
        // Возвращает inserted ID
        return $this->repository->upsert($row);
    }
}

// src/Import/ImportResult.php
class ImportResult
{
    public function __construct(
        public readonly array $processedIds,
        public readonly array $errors,
        public readonly int   $totalRows,
    ) {}
}
🔹 Задачи — Найти все источники роста памяти — Объяснить, почему проблема не воспроизводится на стейджинге — Предложить решение Ставьте → 🔥 если нравится формат. Если нет → 🌚 💬 Решения пишите в комменты под спойлер — сравним подходы.

📊 Queue vs Cron Оба инструмента про «выполнить что-то не прямо сейчас». Но они решают разные задачи, и смешивать их не стоит. Cron — планировщик. Он про время. «Запусти это в 03:00». «Запусти каждые 5 минут». Ему всё равно, что именно запускать — он просто триггерит процесс по расписанию. Queue — очередь. Она про события и нагрузку. «Отправь письмо, когда пользователь зарегистрировался». «Обработай 10 000 строк CSV асинхронно». Очередь не знает про время, она знает про задачи. 🔹 Где Cron уместен — Агрегация данных за период (ночные отчёты) — Очистка устаревших записей — Синхронизация с внешним источником по расписанию — Задачи, которые должны выполняться независимо от пользовательской активности 🔹 Где Queue уместен — Всё, что пользователь спровоцировал, но ждать не должен — Задачи с потенциальными ретраями (внешний API может упасть) — Параллельная обработка (несколько воркеров) — Отправка уведомлений, генерация файлов, вебхуки Если ты пишешь cron-задачу, которая ищет записи со статусом "pending" — ты уже строишь очередь. Используй нормальную: Redis + Laravel Horizon, RabbitMQ, SQS, Beanstalkd. Комбинация: cron запускает job, который кладёт задачи в очередь. Это нормально — диспетчер по расписанию и обработчики асинхронно. 🐸 Библиотека пхпшника #элементарный_выбор

✌🏻 У нас две новости — хорошая и плохая! Хорошая: Ваших знаний, скорее всего, хватит, чтобы собрать рабочую демку AI-агента в Colab. 🫡 Плохая: Вы вряд ли выведете его в прод, не обанкротившись на токенах и не слив базу. 🤯 Для защиты от таких сценариев мы полностью пересобрали курс «Разработка AI-агентов». Теперь внутри плотная работа с экономикой ресурсов, дебаг через time-travel в LangGraph, извлечение данных из кривых сканов для RAG и комплаенс по 152-ФЗ.
Если всё ещё сомневаетесь, послушайте голосовое от спикера курса Влада Прошинского, где он объясняет, как правильно тестировать агентов перед релизом.
Программа курса, полный состав спикеров и другие подробности 👈🏻 ВАЖНО! До 5 апреля на курс действует скидка, но свободные места могут закончиться раньше.

⌨️ Топ-вакансий по PHP за неделю PHP разработчик - от 150 000 до 200 000 ₽ - удалёнка Senior Fullstack PHP разработчик - от 250 000 до 350 000 ₽ - удалёнка Lead PHP Developer - до 400 000 ₽ - удалёнка ➡️ Еще больше топовых вакансий — в нашем канале PHP Jobs

📊 Repository Pattern vs Query Builder Repository — это не про «обернуть Eloquent в класс». Это про то, что доменный код не должен знать, откуда берутся данные. Плохой Repository, который можно часто встретить:
class UserRepository {
    public function findActive(): Collection {
        return User::where('status', 'active')->get();
    }
 
    public function findByEmailAndStatus(string $email, string $status): ?User {
        return User::where('email', $email)
                   ->where('status', $status)
                   ->first();
    }
    // ...ещё 40 методов под каждый запрос
}
Это не Repository — это коллекция запросов в обёртке. Домен по-прежнему диктует методы через свои нужды, а репозиторий распухает. Хороший Repository работает с агрегатами и скрывает детали хранения:
interface UserRepository {
    public function findById(UserId $id): ?User;
    public function findByEmail(Email $email): ?User;
    public function save(User $user): void;
    public function remove(User $user): void;
}
Всё остальное — спецификации, критерии, query objects. Или честный Query Builder там, где это не домен. Где Query Builder напрямую оправдан: — Read-модели (CQRS: команды через домен, запросы — прямо в БД) — Отчёты, дашборды, агрегации — там нет смысла гидрировать объекты — Простые CRUD-экраны без доменной логики
// Это нормально для read-модели
$stats = DB::table('orders')
    ->selectRaw('status, COUNT(*) as count, SUM(amount) as total')
    ->groupBy('status')
    ->get();
Пытаться пропустить это через Repository с Order-сущностями — оверинжиниринг. Правило: Repository живёт на границе домена. Если у тебя нет домена, нет смысла в Repository. Если домен есть, Repository скрывает инфраструктуру, а не просто переносит запросы в другой файл. 🐸 Библиотека пхпшника #элементарный_выбор

#байтовый_юмор
#байтовый_юмор

📊 str_contains / str_starts_with vs strpos strpos возвращает int|false. Это создаёт одну конкретную проблему: проверку на false нужно делать строго:
// Классическая ошибка
if (strpos($url, 'admin')) {
    // Не выполнится, если 'admin' в позиции 0
}
 
// Правильно
if (strpos($url, 'admin') !== false) {
    // Окей
}
Этот паттерн !== false живёт в кодбазах как ритуал, смысл которого половина команды уже не помнит. PHP 8.0 дал str_contains, str_starts_with, str_ends_with. Они возвращают bool. Просто bool.
if (str_contains($url, 'admin')) { ... }
if (str_starts_with($route, '/api')) { ... }
if (str_ends_with($file, '.blade.php')) { ... }
Никакого !== false. Никакой магии с позицией 0. Что осталось за strpos: — Нужна позиция вхождения, а не факт наличия — Нужен offset для поиска со смещением — substr_count, substr_replace всё ещё работают с позициями
$pos = strpos($text, '{{');
$end = strpos($text, '}}', $pos);
// Здесь strpos оправдан — тебе нужны числа
Про производительность: str_contains не медленнее strpos на коротких строках. На длинных — профилируй конкретный кейс, не гадай. Короткий вывод: str_contains и компания — это не синтаксический сахар. Это правильный тип возврата для правильного вопроса. 🐸 Библиотека пхпшника #элементарный_выбор

✔️ PHP-тест: Exception handling + PDO транзакции + молчаливая потеря данных Код выглядит аккуратно. Но данные теряются, и никто не знает почему 👇 📦 Задание Есть сервис для обработки платежей. Код покрыт тестами, транзакции есть, ошибки логируются. На проде раз в несколько дней часть платежей пропадает — в БД нет записи, в логах нет ошибок, пользователь уверен что оплатил.
// src/Payment/PaymentService.php
class PaymentService
{
    public function __construct(
        private PDO        $pdo,
        private Logger     $logger,
        private Notifier   $notifier,
    ) {}

    public function process(PaymentDTO $dto): bool
    {
        try {
            $this->pdo->beginTransaction();

            $paymentId = $this->insertPayment($dto);
            $this->updateBalance($dto->userId, $dto->amount);
            $this->insertAuditLog($paymentId, $dto);

            $this->pdo->commit();

            $this->notifier->sendReceipt($dto->userId, $paymentId);

            return true;

        } catch (NotificationException $e) {
            $this->logger->warning('Receipt failed', ['error' => $e->getMessage()]);
            return true;

        } catch (Throwable $e) {
            $this->logger->error('Payment failed', ['error' => $e->getMessage()]);
            $this->pdo->rollBack();
            return false;
        }
    }

    private function insertPayment(PaymentDTO $dto): int
    {
        $stmt = $this->pdo->prepare(
            'INSERT INTO payments (user_id, amount, status) VALUES (?, ?, ?)'
        );
        $stmt->execute([$dto->userId, $dto->amount, 'pending']);
        return (int) $this->pdo->lastInsertId();
    }

    private function updateBalance(int $userId, float $amount): void
    {
        $stmt = $this->pdo->prepare(
            'UPDATE balances SET amount = amount - ? WHERE user_id = ?'
        );
        $stmt->execute([$amount, $userId]);

        if ($stmt->rowCount() === 0) {
            throw new \RuntimeException("Balance record not found for user $userId");
        }
    }

    private function insertAuditLog(int $paymentId, PaymentDTO $dto): void
    {
        // Пишем в отдельную audit БД через отдельное соединение
        $this->auditPdo->prepare(
            'INSERT INTO audit_log (payment_id, user_id, amount) VALUES (?, ?, ?)'
        );
        // ... execute
    }
}
🔹 Задачи — Найти сценарий, при котором платёж коммитится в БД, но return true не доходит до контроллера — и данные считаются потерянными — Объяснить проблему — Предложить исправленную структуру Ставьте → 🔥 если нравится формат. Если нет → 🌚 💬 Решения пишите в комменты под спойлер — сравним подходы.

🧠 array_map vs foreach Многие считают array_map более "функциональным" и современным. Но есть нюанс. Бенчмарк на массиве из 100 000 элементов:
// array_map — ~12ms
$result = array_map(fn($x) => $x * 2, $items);
 
// foreach — ~6ms
$result = [];
foreach ($items as $x) {
    $result[] = $x * 2;
}
foreach в 1.5–2 раза быстрее на больших массивах, потому что array_map создаёт замыкание и имеет overhead на каждый вызов callback. Когда всё равно использовать array_map? Когда важна читаемость, а массив маленький (до ~1000 элементов) — разница незаметна. Не оптимизируйте там, где это не нужно.
// Читаемо и достаточно быстро для небольших коллекций
$emails = array_map(fn($u) => $u->email, $users);
💡 Правило: сначала профилируйте, потом оптимизируйте. Blackfire и Xdebug в помощь. Библиотека пхпшника #vardump

#байтовый_юмор
#байтовый_юмор

😱 Если ваш продукт не умеет отдавать данные в формате, понятном AI-агенту, то вас просто не существует Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности. Как адаптировать продукт и не исчезнуть из выдачи: — интегрировать MCP и A2A-взаимодействие, чтобы агенты могли вас читать; — научиться контролировать стоимость (лимиты, кэш, роутинг между моделями); — настроить AgentOps: трейсинг, логирование и отлов регрессий. Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях. Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше. Зафиксировать цену и начать деплоить агентов без слива бюджета 👈