Библиотека пхпшника | 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
💡 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
В чем разница между '==' и '===' ?

Нестрогое сравнение («==»): При использовании двойного знака равенства PHP сравнивает значения операндов после их преобразования в общий тип данных. Например, 5 == '5' вернет true, потому что PHP преобразует строку '5' в целое число 5 перед сравнением.

Строгое сравнение («===»): При использовании тройного знака равенства PHP сравнивает не только значения операндов, но и их типы данных. Это означает, что для того чтобы выражение было истинным, значения операндов должны быть одинаковыми и одного типа. Например, 5 === '5' вернет false, потому что типы операндов различны.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🌚5👍2🎉2🤔1
📂 Шпаргалка по вводу-выводу

Чтобы не гуглить каждый раз: как читать из STDIN, быстро проглатывать целый файл, дописывать в конец и копировать потоки — собрали базовые, но практичные примеры.

▪️ Чтение одной строки из STDIN:
<?php
$line = trim(fgets(STDIN)); // читает строку до перевода строки
echo "Введено: $line\n";

Основано на CLI-константе STDIN.

▪️ Чтение всего STDIN:
<?php
$all = stream_get_contents(STDIN); // либо file_get_contents('php://stdin')
echo $all;

php://stdin — стандартный поток ввода процесса PHP.

▪️ Чтение файла целиком:
<?php
$data = file_get_contents('file.txt');
if ($data === false) {
fwrite(STDERR, "Не удалось прочитать файл\n");
exit(1);
}
echo $data;


file_get_contents()
— предпочтительный способ прочитать файл в строку.

▪️ Построчное чтение файла:
<?php
$fh = fopen('file.txt', 'r');
if (!$fh) { die("Не удалось открыть файл\n"); }

while (($line = fgets($fh)) !== false) {
echo $line; // обработка строки
}
fclose($fh);


Используем классический цикл с fgets().

▪️ Запись в файл (перезапись):
<?php
$bytes = file_put_contents('out.txt', "Привет, PHP!\n", LOCK_EX);
if ($bytes === false) {
die("Ошибка записи\n");
}


file_put_contents() перезапишет файл (или создаст, если нет). Можно добавить LOCK_EX для блокировки.

▪️ Запись в файл (добавление в конец):
<?php
$ok = file_put_contents('out.txt', "Новая строка\n", FILE_APPEND | LOCK_EX);
if ($ok === false) { die("Ошибка записи\n"); }


Флаг FILE_APPEND дописывает, а не перезаписывает.

▪️ Копирование файлов (быстро и потоково):
<?php
$src = fopen('src.txt', 'r');
$dst = fopen('dst.txt', 'w');
if (!$src || !$dst) { die("Ошибка открытия файлов\n"); }

$copied = stream_copy_to_stream($src, $dst); // копирует весь остаток
fclose($src);
fclose($dst);

echo "Скопировано байт: $copied\n";


stream_copy_to_stream() копирует данные из одного потока в другой (удобно и для сетевых/памятных потоков).

▪️ Работа с буфером (in-memory I/O):
<?php
$buf = fopen('php://temp', 'r+'); // авто-переключение в файл при больших объёмах
fwrite($buf, "Hello, ");
fwrite($buf, "World!");
rewind($buf);
echo stream_get_contents($buf); // -> Hello, World!
fclose($buf);


php://temp/php://memory — удобные «псевдо-файлы» для буферизации в памяти.

Библиотека пхпшника
👍7🔥21
💡 Не передавай Request вглубь приложения

// 
class OrderService {
public function create(Request $request): Order {
return Order::create([
'user_id' => $request->user()->id,
'amount' => $request->amount,
]);
}
}

//
class OrderService {
public function create(int $userId, float $amount): Order {
return Order::create([
'user_id' => $userId,
'amount' => $amount,
]);
}
}


Сервис не должен знать что такое HTTP. Он принимает данные, а не запрос. Протестировать первый вариант — боль. Второй вызываешь с двумя числами.

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

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21💯6👏1🤩1
✔️ PHP-тест: Static state + OPcache + Preloading

Классический баг, который ломает прод и не воспроизводится локально 👇

📦 Задание

Команда добавила preloading в production для ускорения.

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

На dev-машинах не воспроизводится. Найдите проблему в коде:
// preload.php 
require_once 'src/Config.php';
require_once 'src/UserContext.php';
require_once 'src/RequestPipeline.php';

// config/app.php
class Config
{
private static array $data = [];
private static bool $loaded = false;

public static function load(string $env): void
{
if (self::$loaded) {
return;
}
self::$data = parse_ini_file("config/{$env}.ini");
self::$loaded = true;
}

public static function get(string $key): mixed
{
return self::$data[$key] ?? null;
}
}

// src/UserContext.php
class UserContext
{
private static ?array $current = null;

public static function set(array $user): void
{
self::$current = $user;
}

public static function get(): ?array
{
return self::$current;
}

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

// src/RequestPipeline.php
class RequestPipeline
{
private static array $middlewareResults = [];

public static function addResult(string $key, mixed $value): void
{
self::$middlewareResults[$key] = $value;
}

public static function getResult(string $key): mixed
{
return self::$middlewareResults[$key] ?? null;
}

public static function reset(): void
{
self::$middlewareResults = [];
}
}

// public/index.php
Config::load($_ENV['APP_ENV'] ?? 'production');

$user = Auth::check($_SERVER['HTTP_AUTHORIZATION'] ?? '');
UserContext::set($user);

RequestPipeline::addResult('ip', $_SERVER['REMOTE_ADDR']);
RequestPipeline::addResult('ua', $_SERVER['HTTP_USER_AGENT'] ?? '');

$app->handle(ServerRequest::fromGlobals());


🔹 Задачи

— Объяснить, почему при preloading статические свойства классов ведут себя иначе, чем без него, и как это связано с жизненным циклом worker-процесса.
— Объяснить, чем классы отличаются по характеру утечки
— Предложить архитектурное решение: как правильно управлять request-scoped состоянием в long-running процессах

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

💬 Решения пишите в комменты под спойлер — сравним подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥13👍21👏1
🎮 Балансировка нагрузки для UDP-сервисов

Если необходимо распределить трафик между несколькими UDP-серверами, то решение можно найти в книге «Nginx Cookbook: Advanced Recipes for High-performance Load Balancing» автор показывает использование модуля stream с параметром udp для балансировки нагрузки на уровне транспортного слоя.

Пример кода
stream {
upstream ntp {
server ntp1.example.com:123 weight=2;
server ntp2.example.com:123;
}

server {
listen 123 udp;
proxy_pass ntp;
}
}


Преимущества

— Поддержка балансировки для UDP-сервисов.
— Гибкая настройка весов серверов.
— Резервирование серверов для повышения надёжности.

Еще больше полезных книг — в нашем канале @progbook
Please open Telegram to view this post
VIEW IN TELEGRAM
👍42🔥2
Самый востребованный навык в ИТ в 2026-м — навык создания ИИ-агентов

Мы полностью переработали курс «Разработка AI-агентов» под реалии 2026 года. Никакой долгой теории — с самого начала пишем код. Обучать и делиться набитыми шишками будут эксперты-практики из Газпромбанка, Альфа-Банка и других бигтехов.

В программе:

— архитектура автономных систем с тестированием, ReAct-циклами и контролем токенов;
— практическая работа с актуальными фреймворками LangGraph, AutoGen, MCP и CrewAI;
— настройка продвинутого RAG для парсинга документов и точного поиска;
— внедрение решений с учётом действующего законодательства (152-ФЗ);
— дипломная работа, за основу которой можно взять свой рабочий проект или задачу, которую предложим мы.

Эксперты поделятся инсайтами из реального продакшна — тем, о чём вам никогда не расскажет ни одна нейросеть.

Запись первого открытого вебинара, на котором мы вместе с руководителем AI-направления в Альфа-Банке Полиной Полуниной пилили агента в прямом эфире.


Ах да, чуть не забыли! Дарим промокод AGENTSWEB на скидку 10 000 рублей и два курса сверху при покупке до 15 марта 🎁

Стать AI-инженером
🥱6🌚1
⚡️ Вы кешируете запросы в Redis, но забыли про OPcache?

PHP компилирует каждый .php-файл в байткод при каждом запросе — если не настроен OPcache. Это означает лишние CPU-циклы на парсинг даже самого тривиального хелпера.

Минимальный конфиг для прода:

; включаем
opcache.enable=1
opcache.enable_cli=1

; кол-во кешируемых файлов (>= числа файлов в проекте)
opcache.max_accelerated_files=20000

; размер разделяемой памяти (MB)
opcache.memory_consumption=256

; кешируем строки — экономим RAM
opcache.interned_strings_buffer=16

; в продакшне: 0 (не проверять изменения файлов)
opcache.validate_timestamps=0


Почему validate\_timestamps=0 в проде?

При каждом запросе PHP проверяет mtime файла на диске. На высоких RPS — это сотни лишних stat()-syscall'ов в секунду. Инвалидируйте кеш вручную через opcache_reset() или перезапуск PHP-FPM при деплое.

💡 Хотите проверить, что лежит в кеше и сколько памяти занято? Используйте opcache_get_status() — или поставьте opcache-gui для визуального мониторинга.

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

#vardump
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🔥1