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

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

Учиться у нас: clc.to/M561SQ

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

РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b
Download Telegram
🔍 Работа с sed

Нужно массово заменить строку во всех файлах проекта? sed -i — замена прямо в файлах, без открытия редактора, без скриптов.

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

— Массовый рефакторинг: переименовать endpoint, обновить URL, сменить конфиг.
— Работает с пайпами и можно комбинировать с find и grep.
— Поддерживает регулярки, а не просто текстовая замена.

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

— Замена в файле: sed -i 's/old-api/new-api/g' config.yaml
— Во всех файлах рекурсивно: find . -name "*.yaml" -exec sed -i 's/old-api/new-api/g' {} +
— Удалить строки с паттерном: sed -i '/DEBUG/d' app.log
— Вставить строку после совпадения: sed -i '/server {/a\ listen 443 ssl;' nginx.conf
— На macOS: sed -i '' 's/old/new/g' file.txt (пустой суффикс бэкапа)

💡 Перед массовым sed -i всегда делайте dry run: grep -r "old-api" --include="*.yaml" — убедитесь, что замена затронет только нужные файлы. И коммитьте перед заменой, git diff покажет, если что-то пошло не так.

🐸 Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
😁4👍2🔥2
🐘 В php.ini канала нашли подозрительную настройку

stories.enabled = Off
extra_formats.enabled = Off
admin.mood = tired


Хотим поправить конфиг и включить сторис.

Туда удобно выносить короткие PHP-шпаргалки, вопросы с собесов, мини-разборы, опросы и ссылки, которые не всегда тянут на отдельный пост.

Помочь просто → оформить буст канала.

🐸 Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
1😁11🥱5👍4👏1
🔥 PHP 8.5 завёз пайпы

Тот самый |>, которого ждали с 2016-го. Три RFC, Ларри Гарфилд, «третий раз — заветный».
$slug = $title
|> trim(...)
|> strtolower(...);


Читается сверху вниз, а не выворачивается наизнанку. Но скажем честно:

— чистый сахар, те же опкоды, что и временные переменные;
— (...) в каждом шаге мозолит глаз;
— стрелочные функции надо оборачивать в скобки;
— без PFA многоаргументные функции в пайп не засунешь;
— а куда воткнуть var_dump посреди a |> b |> c?

Что думаете, это шаг к читаемому функциональному PHP или сахарок, который уже раздражает в ревью?

💬 Пишите мнение в комменты

🐸 Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
😢14👍3😁3🥱3💯2
Уже сегодня в 19:00 (МСК) стартует наш открытый урок!

Знаем, летом хочется отложить учёбу на осень. Но пока остальные отдыхают 😅, мы предлагаем без лишней конкуренции прокачать свой workflow и начать закрывать тикеты в три раза быстрее.

Тема:
«AI-инструменты в разработке: пишем код быстрее»


Мы покажем живой разбор реального проекта: как с помощью AI-ассистентов мгновенно разбираться в чужой кодовой базе, искать нужные участки и собирать Pull Request. Только рабочие промпты, которые сэкономят вам часы рутины.

🎙 Спикер — Ольга Лукьянова, руководитель команды в SourceCraft (18+ лет развивала инструменты в JetBrains и Huawei).

👉 Узнать, как ускорить разработку с AI
❗️ Новый релиз

В начале месяца вышел TrueAsync 0.7.0

Версия определяет необходимый API для асинхронного программирования. Релиз соединяет потоки и корутины в единое целое, позволяя комбинировать CPU BOUND/IO BOUND задачи.

Дополнительное расширение-сервер на С помогает использовать async серверные приложения.

🐸 Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥3🤔2
👀 Умеете строить предсказуемую архитектуру с ИИ? Станьте спикером Proglib academy

Мы в Proglib.academy запускаем курс по Spec-Driven Development (SDD) — учим разработчиков управлять ИИ-агентами (Cursor, Copilot, Claude) через спецификации, контекст и тесты, чтобы не перепроверять за нейросетью каждую строку.

Для этого курса мы ищем классных спикеров-практиков.


➡️ Что требуется от вас?

BigTech бэкграунд: опыт работы разработчиком, тимлидом или архитектором в крупных технологических компаниях.
Опыт управляемой разработки с ИИ: вы на практике знаете, как встроить AI-инструменты в личный или командный workflow (от постановки задачи до ревью AI-кода).
Системный подход: умение превращать хаотичную генерацию кода в предсказуемый инженерный процесс (работа с архитектурой, чек-листами, легаси и покрытием тестами).

➡️ Что мы предлагаем?

● Достойную оплату за подготовку материалов и проведение занятий.
● Мощное продвижение личного бренда через медиаресурсы Proglib (наша аудитория — 1 млн+ айтишников).
● Возможность публиковать свои экспертные материалы и статьи на наших площадках.
● Доступ к сильному и закрытому профессиональному сообществу.

Также мы ищем консультанта программы.

Если вы практикующий эксперт и готовы помочь нам отвалидировать программу курса, дать рекомендации по актуальности тем и финальным результатам обучения — мы вас очень ждем.

➡️ Как с нами связаться:

Telegram: @alinaa_kh
E-mail: alina@proglib.io
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱1
⌨️ Топ-вакансий по PHP за неделю

Разработчик PHP — удалёнка — Реактив

Senior/Lead Backend Developer — офис (Москва) — ECOS

Senior Full-stack разработчик (PHP) — удалёнка — Miractal

➡️ Еще больше топовых вакансий — в нашем канале PHP Jobs
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
🤖 Запускаем новый курс: «Spec-Driven Development»!

Всем надоело, что ИИ-агенты (Cursor, Claude) генерируют сотни строк хаотичного кода, который приходится переписывать. Дело не в нейросети, а в том, что вы заставляете её угадывать условия задачи.

На курсе вы освоите методологию SDD (Spec-Driven Development) — управление ИИ через спецификации (спеки) и тесты вместо «вайб-кодинга».

Как это работает?

До генерации кода вы фиксируете в спеке контракты, инварианты и граничные случаи. Документ четко определяет ЧТО делать, сводя лотерею в PR к нулю.

За 8 недель с экспертами из BigTech вы:

🔹 Встроите ИИ в личный или командный workflow.
🔹 Превратите генерацию кода в предсказуемый инженерный процесс.
🔹 Перестанете перепроверять за моделями каждую строчку.

📖 Полный разбор методологии с примерами и готовый промпт для генерации спеки — в нашей статье

👉 Освоить SDD и ускорить разработку
ℹ️ Eloquent Query Classes: дать важному запросу имя

Eloquent отличный слой работы с БД, и большую часть времени where()->with()->paginate() прямо в контроллере или джобе — это нормально. Лишняя абстракция на каждый чих только мешает.

Но проект растёт, и часть запросов перестаёт быть деталью реализации. Они становятся частью бизнес-логики.

Один и тот же фильтр всплывает в дашборде, экспорте, отчёте, фоновой джобе и API. Дублируешь — копии разъезжаются. Прячешь в модель, она пухнет от скоупов и статиков.

В этот момент запросу пора дать имя.

🔹 Что это

Query Class — это Action-паттерн, применённый к запросам. Один публичный вход — handle(). Принимает параметры, строит/выполняет запрос, возвращает результат: коллекцию, пагинатор, агрегат, число затронутых строк или Builder, если вызывающему нужно продолжить композицию.

final readonly class PendingOrdersQuery
{
public function handle(?int $merchantId = null, int $perPage = 50): LengthAwarePaginator
{
return Order::query()
->with(['customer', 'payment'])
->whereIn('status', [OrderStatus::Pending, OrderStatus::PaymentFailed])
->where('created_at', '<=', now()->subMinutes(15))
->when($merchantId !== null,
fn (Builder $q) => $q->where('merchant_id', $merchantId))
->latest()
->paginate($perPage);
}
}


Контроллер больше не знает определения «заказов, требующих внимания». Это определение теперь называется PendingOrdersQuery.

🔹 Это НЕ репозиторий

Репозиторий обычно оборачивает каждый метод модели в generic-CRUD и притворяется, что БД нет. Query Class делает обратное: не прячет Eloquent, а централизует один конкретный важный запрос. Репозиторий = источник данных. Query Class = одна операция против БД с чёткой целью.

🔹 А чем плохи local scopes?

Ничем. Для переиспользуемого ограничения, которое естественно принадлежит модели, скоуп — первый инструмент. Query Class уместен, когда запрос перерос простое ограничение: координирует несколько скоупов, тащит кучу опциональных фильтров, рулит eager loading под конкретный экран, возвращает агрегаты, используется из нескольких точек или требует отдельных тестов.

И они отлично работают вместе: модель владеет доменным ограничением (needingAttention()), Query Class — сценарием использования БД.

🔹 handle() возвращает результат или Builder?

Единый результат — выполняй внутри (->count(), ->paginate()). Один запрос нужен разным потребителям с разными типами результата — верни Builder:

$articles = new PublishedArticlesQuery()->handle()->paginate(12);
$urls = new PublishedArticlesQuery()->handle()->get();


Только не превращай класс в свалку публичных методов — это снова тот самый generic-репозиторий. Хорошие Query Classes скучные и сфокусированные.

🔹 Писать тоже умеют

Если ценность именно в самой операции с БД, запрос на запись тоже подходит:

final readonly class ExpireAbandonedOrdersQuery
{
public function handle(CarbonImmutable $expiredBefore): int
{
return Order::query()
->where('status', OrderStatus::Pending)
->where('created_at', '<=', $expiredBefore)
->update(['status' => OrderStatus::Expired, 'expired_at' => now()]);
}
}


Но если запись часть бизнес-воркфлоу (сайд-эффекты, диспатч джоб, смена стейта), её место в Action, а не здесь.

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

Когда у операции есть бизнес-смысл: CustomersEligibleForDiscountQuery, InvoicesReadyToBeChargedQuery. Когда запрос повторяется, тяжёлый по фильтрам/eager loading, живёт в отчётах и фоне, должен тестироваться отдельно, а модель уже захлёбывается скоупами. Бонус — онбординг: новичок найдёт SearchOrdersQuery быстрее, чем цепочку в недрах контроллера.

🔹 Когда НЕ использовать

Article::findOrFail($id) не нуждается в FindArticleByIdQuery. Если имя класса просто дублирует метод Eloquent, если запрос в одном месте и прост, если скоуп уже всё выражает — не плоди классы. Начинай с чистого Eloquent. Выделяй Query Class, когда запрос это заслужил.

🔹 Тесты

Тестируем не Eloquent (его уже протестировали в Laravel), а наши правила: какие записи попадают, какие отсекаются, в каком порядке. Один тест на дефолтное поведение + точечные на важные фильтры и рискованные края. Комбинаторика всех фильтров не нужна.

🔹 Пять правил на каждый день

— Имя по бизнес-вопросу (PendingOrdersQuery), а не по операции (GetOrdersQuery)
— С записями избирательно: бизнес-правила → Action
— Без абстрактных базовых классов, пока нет реального дублирования
— Один публичный метод handle(), остальное private
— Не прячь Eloquent ради пряток. Возвращать Builder нормально

Ценность паттерна не в количестве классов, а в том, что код становится легче понимать, менять и доверять ему со временем.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍83🔥2😁1
🎬 Где ломаются архитектуры ИИ-агентов и как этого избежать: запись урока от Proglib.Academy и cloud․ru

Proglib.аcademy вместе с cloud․ru провели вебинар, где разобрали реальные боли проектирования автономных систем. Вы просили запись встречи — она уже в открытом доступе!

Что внутри:

— критерии выбора между одним агентом и мультиагентной системой;
— разбор популярных архитектурных ошибок;
— реальные ограничения современных ИИ-агентов;
— практические рекомендации по проектированию агентных систем.

👉 Посмотреть запись можно тут:
VK
YouTube
✔️ PHP-тест: статус, которого нет в коде

Деплоя и релиза ещё не было, а 500-е посыпались сами собой 👇

📦 Задание

Интернет-магазин. Поддержка через админку добавила новый статус заказа refunded (возврат). Нужно было для отчётности, в БД просто появилось новое значение. Через час часть страниц «Мои заказы» начала отдавать 500. Падают только заказы, которым проставили новый статус.
// src/Order/OrderStatusLabel.php
class OrderStatusLabel
{
public function render(string $status): string
{
return match ($status) {
'new' => 'Новый',
'paid' => 'Оплачен',
'shipped' => 'Отправлен',
'delivered' => 'Доставлен',
'cancelled' => 'Отменён',
};
}
}

// src/Order/OrderCard.php
class OrderCard
{
public function __construct(private readonly OrderStatusLabel $label) {}

public function build(Order $order): array
{
return [
'id' => $order->getId(),
'status' => $this->label->render($order->getStatus()),
];
}
}


🔹 Задачи

— Объяснить, чем поведение match тут отличается от switch и почему это привело к 500
— Предложить способ сделать код устойчивым к новым значениям, но НЕ замаскировать реальные баги

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

💬 Решения пишите в комменты под спойлер — сравним подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥3🤔1