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

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

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

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

РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b
Download Telegram
👍 На курсе по контролируемой разработке AI-агентов мы будем разбирать ровно то, о чём говорит Владислав в голосовом, но уже в формате системной практики.

📅 Старт курса — 20 апреля.

Если хотите разобраться, как строить управляемые агентные системы:
➡️ Присоединяйтесь.

P.S. С первого занятия будет практика: код и разбор реальных ошибок, а не только теория.
Please open Telegram to view this post
VIEW IN TELEGRAM
🐘 PHP для начинающих (и напоминание для опытных)

🔹 Eloquent Relationships или почему связи это не страшно

Большинство новичков понимают модели. Один класс — одна таблица, всё логично.

Страшно становится, когда таблицы нужно связывать между собой. В голове сразу всплывают JOIN-ы из курса по SQL, и хочется закрыть ноутбук.

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

// User.php
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}

// Post.php
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}


Всё. Laravel сам догадается, что posts.user_id ссылается на users.id — по соглашению об именовании. Теперь можно писать читаемый код:

// Все посты пользователя
$user->posts;

// Автор конкретного поста
$post->user->name;

// Посты только опубликованные
$user->posts()->where('published', true)->get();


Никаких JOIN-ов вручную. Никакого WHERE user_id = ?. Ты работаешь с объектами, а не с сырым SQL.

Три связи, которые покрывают 90% случаев

▪️ hasMany — у пользователя много постов
▪️ belongsTo — пост принадлежит пользователю
▪️ belongsToMany — пост имеет много тегов, тег стоит на многих постах (промежуточная таблица)

Связи — это просто способ сказать Laravel: «вот как мои таблицы соотносятся». Дальше он разберётся сам.

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

#php_азбука
👍5🔥1
💡 Бесплатный таймер, который уже запущен

Не городи microtime(true) в начале index.php, когда PHP сделал это за тебя:
//  Часто вижу
define('APP_START', microtime(true));
// ... где-то в конце
$elapsed = microtime(true) - APP_START;

// Уже есть
$elapsed = microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'];


Разница принципиальная. APP_START фиксирует момент после автозагрузки, DI-контейнера и прочего bootstrap'а. REQUEST_TIME_FLOAT — реальный старт запроса на уровне PHP-FPM.

// Логируй реальное время ответа в footer или middleware
header('X-Response-Time: ' . round(
(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 2
) . 'ms');


⚠️ Ловушки

— В CLI REQUEST_TIME_FLOAT есть, но равен моменту запуска скрипта.
— Не путай с REQUEST_TIME (int, секунды) — для замеров он бесполезен.

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

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥43
🔥 Named arguments — удобство, которое ломает рефакторинг

// Переименовал параметр — и где-то тихо упало
function createUser(string $name, bool $isActive): void {}

createUser(name: 'Ivan', active: true); // Fatal


Имя параметра теперь публичный контракт. Rector, IDE-рефакторинг, переименование в наследнике — всё это теперь breaking change.

💬 А вы юзаете named arguments в публичном API или только внутри?

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

#междусобойчик
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5👍1🔥1
✔️ PHP-тест: Fibers + замыкания в Laravel

Классическая ловушка с утечкой состояния 👇

📦 Задание

Написали систему обработки платёжных webhook'ов. В логах периодически замечают, что у одной транзакции записывается merchant_id другой. Баг плавающий, воспроизводится только под нагрузкой. Найдите проблему и исправьте:

class MerchantContext
{
private static ?string $currentMerchantId = null;

public static function set(string $id): void
{
self::$currentMerchantId = $id;
}

public static function get(): ?string
{
return self::$currentMerchantId;
}

public static function clear(): void
{
self::$currentMerchantId = null;
}
}

class WebhookProcessor
{
public function handle(WebhookPayload $payload): void
{
MerchantContext::set($payload->merchantId);

$fiber = new Fiber(function () use ($payload): void {
$result = $this->validateSignature($payload);

// симулируем I/O — запрос к внешнему сервису
Fiber::suspend();

$this->auditLogger->log(
'Webhook processed for: ' . MerchantContext::get(),
['amount' => $payload->amount]
);
});

$fiber->start();
// ... другие файберы запускаются здесь
$fiber->resume();
}
}


🔹 Задачи

— Объяснить, почему MerchantContext::get() после resume() может вернуть merchant_id другого запроса
— Исправить так, чтобы контекст не терялся при переключении между файберами

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

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

Простая команда на случай, когда надо быстро и в удобном формате прочитать CSV-файл в терминале:
$ cat inventory.csv | column -t -s,


Флаг -s указывает на использование запятых в качестве разделителей, а -t форматирует выходные данные в чистую таблицу.

📍 Навигация: ВакансииЗадачиВопросы с собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥21
💥 Открытый вебинар | ИИ-агенты в продакшене: от хайпа к деньгам

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

Полина Полунина, руководитель AI-направления Альфа-Банка, расскажет честно:

▪️ Чем агент отличается от «просто GPT с промптом» и когда бизнесу достаточно обычного LLM
▪️ 3 реальных кейса из корпоративной среды: что взлетело, а что нет
▪️ Live-демо работающего агента
▪️ ТОП-5 граблей, на которые наступают команды при внедрении

⏱️ 10 марта в 19:00 (МСК)

🎁 Участники получат промокод на скидку на самый полный курс по ИИ-агентам

👉 Регистрируйся
🥱21
💡 when() в Eloquent — условные запросы без if-else

Если пишешь вот так:
$query = User::query();

if ($request->has('active')) {
$query->where('active', true);
}

if ($request->has('role')) {
$query->where('role', $request->role);
}

$users = $query->get();


У Eloquent есть when() и он делает это элегантно:
$users = User::query()
->when($request->has('active'), fn($q) => $q->where('active', true))
->when($request->role, fn($q, $role) => $q->where('role', $role))
->get();


Второй аргумент when() — это значение условия, оно же автоматически передаётся третьим параметром в колбэк. Не нужно захватывать переменную через use.

Используй это для фильтрации по параметрам запроса, построения поисковых форм и любых условных скоупов. Код становится читаемым как pipeline, а не лестница из if-else.

⚠️ Ловушка: when('0', ...) — не выполнится, потому что '0' приводится к false. Если важна строка "0" — проверяй явно: when($val !== null, ...).

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

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
😁5👍4🔥21
🤡 Битрикс взял вашего бота в заложники. Выкуп — 50к в год.

Ноябрь 2025: коробочный Битрикс24, бот на Python, всё работает. Потом — тишина, а tcpdump показывает, что события улетают на какой-то curator.pro и там умирают.

Поддержка отвечает честно: «Отправка событий теперь только по подписке на Маркет».

Подождите. Коробка на нашем сервере. Бот на нашем сервере. Почему HTTP-запрос между двумя нашими машинами требует ежегодной оплаты?

Решение нашлось. Никакого curator.pro, никаких чужих серверов, никаких денег. 6 файлов. 5 минут установки. 0 рублей в год.

Как это устроено изнутри и почему автор написал целую статью ради экономии 50к → читайте на Хабре

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

#php_core
Please open Telegram to view this post
VIEW IN TELEGRAM
😁7👍5🔥1
🔥 Guzzle vs cURL напрямую

Каждый проект рано или поздно упирается в HTTP-запросы. И вот тут начинается классика: «а зачем нам Guzzle, если есть встроенный cURL?»

Давай без холивара разберёмся по делу.

🔹 cURL напрямую

$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://api.example.com/users',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $token],
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);


Работает везде, зависимостей ноль. Но каждый запрос — это церемония. Обработка ошибок? Отдельный квест: curl_errno(), curl_error(), ручной парсинг хедеров.

🔹 Guzzle

$client = new Client([
'base_uri' => 'https://api.example.com',
'timeout' => 10,
]);
$response = $client->get('/users', [
'headers' => ['Authorization' => 'Bearer ' . $token],
]);
$data = json_decode($response->getBody(), true);


Исключения из коробки, middleware, retry-логика, async через Promises, mock-клиент для тестов. Это не просто обёртка над cURL — это другой уровень абстракции.

📊 Когда что выбрать


Один-два простых запроса → cURL, не тащи зависимость
Интеграция с внешним API → Guzzle, однозначно
Нужен retry/backoff → Guzzle + HandlerStack
Пишешь библиотеку/пакет → cURL или PSR-18 абстракция
Хочешь нормально тестировать → только Guzzle MockHandler

💬 Что выбираете вы?

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

#элементарный_выбор
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍2💯1
☝️ Уже сегодня: ИИ-агенты в продакшене — инженерный подход к интеграции LLM

Индустрия активно обсуждает потенциал нейросетей, способных автоматизировать бизнес-процессы и заменить целые отделы. Однако реальное внедрение агентов в production вскрывает серьёзные проблемы: разработчикам приходится бороться с непредсказуемыми галлюцинациями моделей, нестабильными API и сложной интеграцией в существующую архитектуру.

Сегодня в 19:00 МСК в рамках нашего курса «Разработка AI-агентов» мы проведём открытый вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке. Будем говорить о нейросетях с позиции жёсткой инженерии.

Разберём три реальных кейса из сурового банковского энтерпрайза, напишем и запустим агента прямо в эфире, честно обсудим грабли, на которые наступает бизнес при интеграции LLM.

Тем, кто придёт на эфир, дадим промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре
😁1🥱1
Часовая готовность: создаём ИИ-агента в прямом эфире

В 19:00 МСК в рамках нашего курса «Разработка AI-агентов» стартует вебинар «ИИ-агенты в продакшене: от хайпа к деньгам». Спикер — Полина Полунина, руководитель AI-направления в Альфа-Банке.

Будет live-демо работающего агента, реальные метрики из корпоративной среды и честный разбор архитектурных граблей — без воды и «успешного успеха».

Всем зрителям эфира дадим эксклюзивный промокод AGENTS на скидку 10 000 ₽ на любой тариф курса.

👉 Занять место на вебинаре
🥱1
⚡️ Как настроить zero-downtime деплой PHP-приложения через GitHub Actions + Deployer

Разбираем правильный пайплайн: атомарный деплой, откат за 10 секунд, нет простоя.

1️⃣ Устанавливаем Deployer

composer require deployer/deployer --dev

Генерируем базовый конфиг:
./vendor/bin/dep init

Выбираем тип проекта (Laravel, Symfony, Common). Получаем deploy.php в корне.

2️⃣ Конфигурируем хосты и пути

// deploy.php
import('recipe/laravel.php');

host('production')
->setHostname('your-server.com')
->setRemoteUser('deploy')
->setDeployPath('/var/www/app')
->setSshMultiplexing(true);

set('shared_files', ['.env']);
set('shared_dirs', ['storage', 'bootstrap/cache']);
set('writable_dirs', ['storage', 'bootstrap/cache']);
set('keep_releases', 5);


keep_releases: 5 — держим 5 последних релизов на сервере. Откат мгновенный.

3️⃣ Понимаем структуру директорий

Deployer создаёт на сервере:
/var/www/app/
├── current -> releases/20250311120000/ # symlink
├── releases/
│ ├── 20250311120000/
│ └── 20250310090000/
└── shared/
├── .env
└── storage/


current — это симлинк. Переключение релиза = атомарная замена симлинка. Nginx видит новый код без перезапуска.

4️⃣ Добавляем кастомные задачи

task('artisan:migrate', function () {
run('cd {{release_path}} && php artisan migrate --force');
});

task('opcache:reset', function () {
run('kill -USR2 $(cat /var/run/php-fpm.pid)');
});

// порядок выполнения
after('deploy:symlink', 'opcache:reset');
before('deploy:symlink', 'artisan:migrate');

Миграции — до переключения симлинка. OPcache сброс — после. Последовательность важна.

5️⃣ GitHub Actions пайплайн

# .github/workflows/deploy.yml
name: Deploy to Production

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'

- name: Install dependencies
run: composer install --no-dev --optimize-autoloader

- name: Deploy
run: ./vendor/bin/dep deploy production -vvv
env:
SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_KEY }}

Секрет DEPLOY_SSH_KEY — приватный ключ деплой-юзера без sudo, только для деплоя.

6️⃣ Настраиваем деплой-юзера на сервере

useradd -m -s /bin/bash deploy
mkdir -p /home/deploy/.ssh
# вставляем публичный ключ
echo "ssh-ed25519 AAAA..." >> /home/deploy/.ssh/authorized_keys
chmod 700 /home/deploy/.ssh && chmod 600 /home/deploy/.ssh/authorized_keys

# права на директорию приложения
chown -R deploy:www-data /var/www/app
chmod -R 775 /var/www/app

PHP-FPM должен работать от www-data. Deployer деплоит от deploy. Группа общая.

7️⃣ Откат при провале

// автоматический откат если задача упала
after('deploy:failed', 'deploy:unlock');

// ручной откат из CLI
./vendor/bin/dep rollback production

Rollback меняет симлинк на предыдущий релиз. Время: ~3 секунды.

📌 Итог

Deployer + symlink-стратегия + GitHub Actions = деплой без простоя, с историей релизов и откатом в одну команду. Больше никакого git pull руками на проде.

Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥4🥱31
⌨️ Топ-вакансий по PHP за неделю

PHP программист — 150 000 - 200 000₽ — удалёнка

PHP программист — до 350 000 ₽ — удалёнка

РНР-разработчик — 250 000 —‍ 450 000 ₽ — гибрид (Москва, Санкт-Петербург)

➡️ Еще больше топовых вакансий — в нашем канале PHP Jobs
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32
🐳 Прокачай Docker CLI

Dockerlings предлагает более 15 упражнений, которые последовательно учат работать с контейнерами, Dockerfile, сетями, томами и многими другими важными аспектами Docker.

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

🔗 Попробовать Docker CLI

Библиотека пхпшника
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍4