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

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

@phpproglib

Все самое полезное для пхпшника в одном канале.

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

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

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

РКН: https://gosuslugi.ru/snet/67a5d13cd6fa92100ee6f68b
Subscribers
10.5K
Photos
1.8K
Videos
31
Links
4.6K

Showing posts older than #6405 · Back to latest

Older Posts 20 shown
Post #6403 2.57K
📊 readonly properties vs private + getter

До 8.1 иммутабельность в value objects эмулировали через private + геттер. Это работало, но создавало шум: конструктор, приватное свойство, метод. Три места ради одной идеи.

// До
class Money {
private int $amount;

public function __construct(int $amount) {
$this->amount = $amount;
}

public function getAmount(): int {
return $this->amount;
}
}


readonly убирает весь этот церемониал:

// После
class Money {
public function __construct(
public readonly int $amount,
) {}
}


Читается как контракт: свойство публично, но записать его можно только один раз при инициализации. Повторная запись → Error, не предупреждение.

Когда readonly не подходит:

1. Нужна ленивая инициализация. readonly нельзя присвоить вне конструктора (до PHP 8.4 с хуками).
2. Клонирование с изменением. clone с readonly требует PHP 8.3 (readonly классы + clone в new static).
3. Моки в тестах. Если тест хочет подменить значение readonly-свойства через рефлексию, получит Error.

PHP 8.2 добавил readonly классы — все свойства автоматически readonly:

readonly class Coordinates {
public function __construct(
public float $lat,
public float $lng,
) {}
}


Хорошо для DTO, value objects, команд и событий. Плохо там, где нужна мутация или частичная инициализация.

Правило простое: если объект концептуально иммутабелен → readonly. Если есть хоть одна причина менять состояние после создания → private + логика в методах.

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

#элементарный_выбор
  • 👍 8
  • 🔥 2
  • 🥱 1
Post #6401 2.44K
🔍 Убийца перфоманса, который можно пропустить в ревью

Классика, которую все знают, но продолжают допускать. Особенно в Eloquent.

🔹 Проблема

$orders = Order::all();

foreach ($orders as $order) {
echo $order->user->name; // SELECT * FROM users WHERE id = ? (на каждой итерации!)
}


🔹 Решение — eager loading

$orders = Order::with('user')->get();
// Теперь 2 запроса вместо N+1


🔹 Как поймать в проде

Подключите debugbar или telescope в dev-среде. Или логируйте запросы вручную:

DB::listen(function ($query) {
Log::info($query->sql, $query->bindings);
});


💡 Если видите один и тот же запрос десятки раз в логах — это он. Ищите все места, где обращаетесь к связям внутри цикла.

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

#vardump
  • 🥱 9
  • 👍 5
  • 👏 1
  • 😢 1
Post #6400 2.35K
Точки роста PHP-разработчика

Наш подписчик спрашивает

«Я PHP-разработчик с опытом 1,5 года. Но ощущаю, что топчусь на месте. Какие навыки стоит развивать, чтобы сдвинуть с мертвой точки через год-два ? Углубляться в фреймворки или лучше прокачивать soft skills?»

Алексей, PHP Developer


💬 Делитесь в комментариях:

— Какие технические навыки необходимы для роста
— Насколько важны фреймворки и архитектура
— Какие soft skills действительно ценят

P.S. Если хотите задать вопрос, заполните нашу гугл-форму. Это займет 5 минут.

#междусобойчик
  • 😁 4
  • 🔥 3
  • ❤ 1
Post #6399 1.97K

Forwarded from Библиотека собеса по PHP | вопросы с собеседований

✔️ PHP-тест: Typed Properties + Lazy Initialization + Объект в статике

Баг, который живёт в проде месяцами и проявляется только под нагрузкой 👇

📦 Задание

Команда пишет модуль биллинга. Ты написал быстрый класс-обёртку для работы с тарифами. Код прошёл ревью, всё работало на стейджинге. В проде через неделю начались жалобы: у части пользователей неправильно считается стоимость. Причём только в пиковые часы.

// src/Billing/TariffCalculator.php
class TariffCalculator
{
private static TariffConfig $config;
private static array $cache = [];

public static function init(array $rawConfig): void
{
self::$config = new TariffConfig($rawConfig);
}

public static function calculate(int $userId, int $units): float
{
$key = $userId . ':' . $units;

if (isset(self::$cache[$key])) {
return self::$cache[$key];
}

$price = self::$config->getBasePrice()
* $units
* self::$config->getUserMultiplier($userId);

self::$cache[$key] = $price;

return $price;
}

public static function resetCache(): void
{
self::$cache = [];
}
}

// src/Billing/TariffConfig.php
class TariffConfig
{
private float $basePrice;
private array $multipliers;

public function __construct(array $config)
{
$this->basePrice = (float) $config['base_price'];
$this->multipliers = $config['multipliers'] ?? [];
}

public function getBasePrice(): float
{
return $this->basePrice;
}

public function getUserMultiplier(int $userId): float
{
return $this->multipliers[$userId] ?? 1.0;
}
}

// bootstrap.php — вызывается один раз при старте воркера
TariffCalculator::init(loadConfigFromDB());

// Где-то в обработчике запроса
$price = TariffCalculator::calculate($user->id, $request->units);


🔹 Задачи

— Найти все архитектурные и логические проблемы в коде (их несколько)
— Объяснить, почему баг проявляется только под нагрузкой и не воспроизводится на стейджинге
— Предложить правильное решение

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

💬 Решения пишите в комменты под спойлер — сравним подходы.
  • 🔥 18
  • ❤ 2
  • 👍 1
  • 🌚 1
Post #6398 2.23K
Почитали тут свежий отчёт по рынку ИИ-ускорителей в РФ: оказывается, 54% компаний тормозят внедрение ИИ исключительно из-за конских цен на инфраструктуру.

Ну, то есть написать пет-проект с вызовом API это задача на вечер, а вот запустить агента в продакшн так, чтобы он не сжёг бюджет отдела за неделю — суровая инженерия.

По сути, сейчас мало уметь собирать RAG. Нужно считать токены, настраивать time-travel дебаг в LangGraph и уметь роутить запросы на лету. Всё это мы учли в обновлённом курсе по разработке AI-агентов, где акцент сделан именно на AgentOps и жёсткий контроль ресурсов.

Также в программе:

— оценка качества, трейсинг и защита от деградации пайплайнов;
— мультиагентные паттерны и интеграция по протоколу MCP;
— локальный деплой Open Source под 152-ФЗ (когда данные нельзя выносить наружу).

Кажется, это единственный адекватный roadmap по переходу от блокнотов к enterprise-решениям.

Прямо сейчас можно урвать курс с увесистой скидкой (49 000 ₽ 62 990 ₽ за базовый тариф и 99 000 ₽ 124 990 ₽ за продвинутый трек), но стоит поторопиться — на потоке осталось всего 5 мест.

👉 Зафиксировать цену и начать собирать агентов, за которых не стыдно в проде
  • 🥱 3
Post #6397 2.06K
⚙️ Laravel Process Pipe

С версии Laravel 10.7 появилась нативная поддержка конвейера процессов (pipe). Теперь можно легко передавать вывод одного процесса на вход другого — прямо из PHP-кода, без костылей.

use Illuminate\Process\Pipe;
use Illuminate\Support\Facades\Process;

$result = Process::pipe(function (Pipe $pipe) {
$pipe->command('cat example.txt'),
$pipe->command('grep -i "laravel"'),
});

if ($result->successful()) {
// ...
}


Это аналог привычного cat example.txt | grep -i "laravel" в терминале, только внутри Laravel.

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

— Обработка файлов и потоков данных без временных переменных
— Чистый и читаемый код вместо вызовов shell_exec
— Удобное тестирование через фейковые процессы

Маленькая фича, но приятная 🙂

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

#vardump
  • 👍 7
  • ❤ 2
  • 😁 1
Post #6395 2.29K
#байтовый_юмор
  • 😁 33
  • 🌚 4
Post #6394 2.45K
🐘 PHP для начинающих (и напоминание для опытных)

🔹 Query Scopes

Смотришь на свой код и замечаешь одно и то же в пяти местах:
->where('status', 'active')->where('deleted_at', null)
->where('status', 'active')->where('deleted_at', null)
->where('status', 'active')->where('deleted_at', null)


Это не переиспользование кода. Это его копирование. Разница важная.

▪️ Local Scope — прячем логику в модель

// User.php
public function scopeActive(Builder $query): Builder
{
return $query->where('status', 'active')
->whereNull('deleted_at');
}

public function scopeVerified(Builder $query): Builder
{
return $query->whereNotNull('email_verified_at');
}


Теперь вместо цепочки условий — читаемый вызов
// Было
User::where('status', 'active')
->whereNull('deleted_at')
->whereNotNull('email_verified_at')
->get();

// Стало
User::active()->verified()->get();


▪️ Scope с параметром


Иногда нужна гибкость. Scope принимает аргументы:
public function scopeOlderThan(Builder $query, int $days): Builder
{
return $query->where('created_at', '<', now()->subDays($days));
}
phpUser::active()->olderThan(30)->get();


▪️ Global Scope — когда условие должно быть всегда


Если SoftDeletes работает по всему приложению — это глобальный скоуп под капотом. Можно написать свой:
// В модели
protected static function booted(): void
{
static::addGlobalScope('tenant', function (Builder $builder) {
$builder->where('tenant_id', auth()->user()?->tenant_id);
});
}


Теперь все запросы к этой модели автоматически фильтруются по тенанту. Без единого where в контроллерах.

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

#php_азбука
  • 👍 10
  • ❤ 5
  • 🔥 2
  • 🥱 1
Post #6393 2.26K
👀 Reli — профилировщик выборки или памяти

Это профилировщик, написанный на PHP, который считывает информацию о запуске виртуальной машины PHP извне процесса.

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

🔗 Github

#инструменты
  • 👍 6
  • 🔥 3
  • ❤ 1
Post #6392 2.18K
#байтовый_юмор
  • 😁 20
  • 👍 4
  • 💯 3
Post #6391 2.23K
⌨️ Топ-вакансий по PHP за неделю

PHP разработчик (Symfony, Rest API) — от 100 000 до 150 000 ₽ — удалёнка

Middle PHP разработчик — от 150 000 до 250 000 ₽ — гибрид/удалёнка (Воронеж)

Team Lead (PHP, Laravel) — от 500 000 ₽ — удалёнка/гибрид (Москва)

➡️ Еще больше топовых вакансий — в нашем канале PHP Jobs
  • 👍 2
  • ❤ 1
  • 🔥 1
Post #6390 2.12K

Forwarded from Библиотека собеса по PHP | вопросы с собеседований

Зачем использовать yield вместо return с массивом?

yield превращает функцию в генератор. Вместо того чтобы собрать все данные в массив и вернуть целиком, функция отдаёт значения по одному, по мере запроса.

Главный профит — память. Если обрабатываешь CSV на 500 тысяч строк, с массивом ты загрузишь всё в RAM разом. С генератором в памяти живёт одна строка. Генератор реализует интерфейс Iterator, с ним работает foreach. Минус — нельзя перемотать назад, обойти можно только один раз. Используй когда данных много, порядок линейный, и случайный доступ не нужен.
  • 👍 10
  • 🔥 3
Post #6389 2.21K
Кажется, мы окончательно перешли от игрушек к суровому AgentOps

Приглашаем на наш обновлённый курс по разработке ИИ-агентов. Никакой воды про «будущее нейросетей», только инженерный подход.

На курсе мы:

— пошагово строим готовые системы на LangGraph, CrewAI и MCP;
— настраиваем кэширование и роутинг, чтобы бот не сожрал токены;
— разбираемся со стейтом, учимся дебажить через time-travel и прикручиваем human-in-the-loop;
— выводим RAG в прод так, чтобы безопасники не завернули архитектуру из-за 152-ФЗ.

В пекло скучные лекции про общую инфраструктуру — сразу фокусируемся на агентных фреймворках и написании кода. Занятия ведут бывалые лиды из Газпромбанка и Альфы, набившие шишки на реальных задачах.

Кстати, на днях мы пилили агента в прямом эфире, если пропустили — есть запись вебинара.


Сегодня последний день, когда можно забрать курс по старым ценам. Базовый тариф сейчас стоит 49 000 ₽ (вместо 62 990 ₽), продвинутый трек — 99 000 ₽ (вместо 124 990 ₽). Если не хочется отдавать всю сумму сразу, есть рассрочка. Торопитесь — на потоке осталось всего 5 мест!

Зафиксировать цену и перейти к сборке своих агентов
Post #6388 2.12K
У «Библиотеки программиста» появился резервный канал в мессенджере MAX

Он нужен исключительно для связи с теми, кто не может следить за обновлениями здесь из-за трудностей с доступом. Поэтому, если вы видите это сообщение, распространите его среди жильцов вашего ЖЭКа.

Контент в MAX будет дублировать телеграмный — основной нашей площадкой был и остаётся Telegram. Надеемся, это временная мера.

Подписаться на «Библиотеку программиста» в MAX
  • 🥱 21
  • 😁 6
  • 👾 4
  • 😢 3
Post #6387 2.18K
📊 match vs switch

Два инструмента, которые делают похожие вещи, но не одинаковые — и разница не стилистическая.

— switch использует нестрогое сравнение (==)
— match использует строгое (===) и является выражением

Вот классический баг, который живёт в каждом втором легаси-проекте:

$status = "0";

switch ($status) {
case 0: // "0" == 0 → true. Вот и приехали.
handleInactive();
break;
case "active":
handleActive();
break;
}


match решает это без магии:

$label = match($code) {
200, 201 => 'success',
301, 302 => 'redirect',
404 => 'not_found',
default => 'unknown',
};


Несколько значений на один arm можно указать через запятую. Результат — значение, не сайд-эффект. Можно прямо в return или аргумент функции.

Про UnhandledMatchError: match без default бросает исключение, если значение не попало ни в один arm. switch молча пропускает. Это не недостаток match — это контракт. Явный фейл лучше тихого игнорирования.

🔹 Когда всё-таки switch:

— нужен fallthrough осознанно
— легаси на PHP 7
— в arm несколько выражений подряд, а не одно возвращаемое значение

Выбор инструмента — это не про стиль. Это про то, какие гарантии тебе нужны от кода.

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

#элементарный_выбор
  • 👍 9
  • 🔥 3
Post #6386 2.16K
#байтовый_юмор
  • 😁 15
  • 👍 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →