Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter
Все самое полезное для пхпшника в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/bca892d6 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b
Show more📈 Analytical overview of Telegram channel Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter
Channel Библиотека пхпшника | PHP, Laravel, Symfony, CodeIgniter (@phpproglib) in the Russian language segment is an active participant. Currently, the community unites 10 698 subscribers, ranking 11 609 in the Technologies & Applications category and 61 312 in the Russia region.
📊 Audience metrics and dynamics
Since its creation on невідомо, the project has demonstrated rapid growth, gathering an audience of 10 698 subscribers.
According to the latest data from 09 June, 2026, the channel demonstrates stable activity. Although there has been a change in the number of participants by -40 over the last 30 days and by 0 over the last 24 hours, overall reach remains high.
- Verification status: Not verified
- Engagement rate (ER): The average audience engagement rate is 15.51%. Within the first 24 hours after publication, content typically collects 8.98% reactions from the total number of subscribers.
- Post reach: On average, each post receives 1 659 views. Within the first day, a publication typically gains 961 views.
- Reactions and interaction: The audience actively supports content: the average number of reactions per post is 11.
- Thematic interests: Content is focused on key topics such as php, laravel, пхпшника, artisan, api.
📝 Description and content policy
The author describes the resource as a platform for expressing subjective opinions:
“Все самое полезное для пхпшника в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/bca892d6
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b”
Thanks to the high frequency of updates (latest data received on 10 June, 2026), the channel maintains relevance and a high level of publication reach. Analytics show that the audience actively interacts with content, making it an important point of influence in the Technologies & Applications category.
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.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.Python и современных фреймворков. Мы не будем учить «общаться» с нейросетью, мы будем строить из неё надёжный инструмент.
✅ Что вы получите:
— понимание того, как управлять логикой агента на уровне кода;
— навыки работы с LangChain и библиотеками оркестрации;
— готовые паттерны для обработки ошибок и галлюцинаций;
— опыт создания систем, которые реально экономят время.
Есть пара мест со скидкой до завтра, решайтесь 👈🏻// 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
Ставьте → 🔥 если нравится формат. Если нет → 🌚
💬 Решения пишите в комменты под спойлер — сравним подходы.// Читаемо и быстро
Cache::get('user:' . $id);
// Явно и тестируемо
public function __construct(
private CacheInterface $cache,
) {}
Скрытые зависимости, нарушение SRP, привязка к фреймворку через __callStatic() — звучит страшно. Но 64% PHP-девов используют Laravel и не парятся.
Как пишете вы — Facades или DI? И считаете ли, что Тейлор красиво «продал» антипаттерн?
💬 Пишите ваше мнение в комментарии
#междусобойчик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 позволяет их «изменить» без рефлексии.
#vardumpsymfony/translation, разберём подходы к хранению переводов, варианты моделей данных и практическую реализацию получения локализованного содержимого через Doctrine.
Урок не для тех, кто хочет решить многоязычность «одной таблицей на всё», не думает о поддержке архитектуры и считает, что локализация заканчивается на переводе кнопок и заголовков.👉 Записаться: https://clc.to/x9D9Pg Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
// 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, это его дизайн. Просто решай осознанно.
🐸 Библиотека пхпшника
#элементарный_выбор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// 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,
) {}
}
🔹 Задачи
— Найти все источники роста памяти
— Объяснить, почему проблема не воспроизводится на стейджинге
— Предложить решение
Ставьте → 🔥 если нравится формат. Если нет → 🌚
💬 Решения пишите в комменты под спойлер — сравним подходы.
Available now! Telegram Research 2025 — the year's key insights 
