#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 3/10
⚡️ Стрілкові функції (Arrow Functions)
Як анонімка, тільки стрункіше
📦 Додано у версії: PHP 7.4
💡 Що дає: компактний синтаксис для коротких функцій, які автоматично бачать змінні з оточення та завжди повертають результат.
🧠 Особливості, які треба знати
— завжди повертають значення
— можуть містити лише один вираз — без
— автоматично успадковують змінні з оточення, без
— читаються як вираз, а не як інструкція.
⚙️ Чому це зручно
— менше шаблонного коду;
— виразність у callback-ах (map, filter, reduce);
— краще читається, особливо в колекціях і стрімах;
— підходить для будь-якого місця, де потрібен мінімалістичний обробник.
🧱 Реальний приклад застосування
🔹 Перетворення масиву
🔹 Фільтрація елементів
🔹 Підрахунок значення
🔹 Простий калькулятор з доступом до зовнішньої змінної
🧭 Висновок
🔥 Якщо тобі потрібен в коді
———
⬅️ Анонімні класи | Генератори ➡️
🚀 Чи знаєш ти, що PHP так вміє? 3/10
⚡️ Стрілкові функції (Arrow Functions)
Як анонімка, тільки стрункіше
📦 Додано у версії: PHP 7.4
💡 Що дає: компактний синтаксис для коротких функцій, які автоматично бачать змінні з оточення та завжди повертають результат.
🧠 Особливості, які треба знати
— завжди повертають значення
— можуть містити лише один вираз — без
{} і багатооператорних блоків;— автоматично успадковують змінні з оточення, без
use($x);— читаються як вираз, а не як інструкція.
⚙️ Чому це зручно
— менше шаблонного коду;
— виразність у callback-ах (map, filter, reduce);
— краще читається, особливо в колекціях і стрімах;
— підходить для будь-якого місця, де потрібен мінімалістичний обробник.
🧱 Реальний приклад застосування
🔹 Перетворення масиву
$prices = [100, 200, 300];
$tax = 0.2;
// ❌ Звичайна анонімна функція
$withTax = array_map(function (int $p) use ($tax) {
return $p * (1 + $tax);
}, $prices);
// ✅ Стрілкова функція
$withTax = array_map(fn(int $p) => $p * (1 + $tax), $prices);
🔹 Фільтрація елементів
$activeUsers = array_filter($users, fn(User $u) => $u->active);
🔹 Підрахунок значення
$total = array_reduce($orders, fn(int $sum, Order $o) => $sum + $o->amount, 0);
🔹 Простий калькулятор з доступом до зовнішньої змінної
$multiplier = 3;
$calc = fn(int $v) => $v * $multiplier;
echo $calc(10); // 30
🧭 Висновок
Стрілкові функції — це лаконічна форма анонімок, створена для чистих, коротких виразів у прямолінійній логіці
🔥 Якщо тобі потрібен в коді
function ($x) use ($y) { return …; } — просто заміни на fn() і відчуй різницю———
⬅️ Анонімні класи | Генератори ➡️
Telegram
Створений щоб помирати
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 2/10
🧩 Анонімні класи
Давня фіча, яку безліч розробників досі ігнорують 🤷♂️
📦 Додано у версії: PHP 7.0
💡 Що дає: можливість створювати клас “на льоту” — без імені, без окремого файлу, просто у місці…
🚀 Чи знаєш ти, що PHP так вміє? 2/10
🧩 Анонімні класи
Давня фіча, яку безліч розробників досі ігнорують 🤷♂️
📦 Додано у версії: PHP 7.0
💡 Що дає: можливість створювати клас “на льоту” — без імені, без окремого файлу, просто у місці…
👍5
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 4/10
🔄 Генератори
🧠 Старий інструмент, який більшість досі не використовує
📦 Додано у версії: PHP 5.5
💡 Що дає: функції з
⚙️ Реальність така
Хоча генератори існують у PHP з 5.5, на співбесідах більшість розробників або не можуть пояснити, де саме вони реально економлять памʼять, або згадують їх лише теоретично — на кшталт "це щось для великих даних". А по практичним кейсам — нуль ідей.
Тому давайте я накину вам трохи ідей як і де їх можна використовувати.
🧩 Як вони працюють насправді
На відміну від звичайних ітераторів чи масивів:
— генератор не знає, скільки буде елементів;
— не знає, чи є наступний;
— не пам’ятає, чи була попередня ітерація;
— однопрохідний — пройшов, і все, повторно не повернешся.
А попри всі ці “обмеження” — він має одну суттєву перевагу:⚡️ він може призупиняти власне виконання, що дозволяє не тримати в памʼяті всі стани, а тільки поточний.
Це не “масив”, а скоріше потік — і саме тому він безцінний у правильному місці.
🧱 Реальні кейси, де yield справді потрібен
🔹 1. Посторінкове читання з БД
🔸 економія памʼяті колосальна — працює навіть на таблицях у сотні тисяч рядків.
🔹 2. Потоковий парсинг великих файлів
💡 читає рядок за рядком — не вантажить весь CSV в памʼять
🔹 3. Потоковий запис результату в файл
⚙️ відправка великих звітів чи експорту — без буферизації, у реальному часі.
🔹 4. Поступове завантаження з API
⚡️ ідеально для стрімінгової обробки даних без буферизації
🔹 5. Обхід великої файлової структури
📁 ідеально для обходу каталогів, навіть якщо їх тисячі
🧭 Висновок
🔥 Якщо ти колись писав скрипт, який падав через out of memory, —
———
⬅️ Стрілкові функції | DateTimeImmutable ➡️
🚀 Чи знаєш ти, що PHP так вміє? 4/10
🔄 Генератори
🧠 Старий інструмент, який більшість досі не використовує
📦 Додано у версії: PHP 5.5
💡 Що дає: функції з
yield, які повертають елементи поступово — замість того, щоб збирати все в памʼяті й віддавати одразу.⚙️ Реальність така
Хоча генератори існують у PHP з 5.5, на співбесідах більшість розробників або не можуть пояснити, де саме вони реально економлять памʼять, або згадують їх лише теоретично — на кшталт "це щось для великих даних". А по практичним кейсам — нуль ідей.
Тому давайте я накину вам трохи ідей як і де їх можна використовувати.
🧩 Як вони працюють насправді
На відміну від звичайних ітераторів чи масивів:
— генератор не знає, скільки буде елементів;
— не знає, чи є наступний;
— не пам’ятає, чи була попередня ітерація;
— однопрохідний — пройшов, і все, повторно не повернешся.
А попри всі ці “обмеження” — він має одну суттєву перевагу:⚡️ він може призупиняти власне виконання, що дозволяє не тримати в памʼяті всі стани, а тільки поточний.
Це не “масив”, а скоріше потік — і саме тому він безцінний у правильному місці.
🧱 Реальні кейси, де yield справді потрібен
🔹 1. Посторінкове читання з БД
function fetchUsers(PDO $db, int $limit = 500): Generator
{
$offset = 0;
while (true) {
$rows = $db->query("SELECT * FROM users LIMIT $limit OFFSET $offset")->fetchAll();
if (!$rows) break;
yield from $rows;
$offset += $limit;
}
}
🔸 економія памʼяті колосальна — працює навіть на таблицях у сотні тисяч рядків.
🔹 2. Потоковий парсинг великих файлів
function readCsv(string $path): Generator
{
$h = fopen($path, 'r');
while (($row = fgetcsv($h)) !== false) {
yield $row;
}
fclose($h);
}
💡 читає рядок за рядком — не вантажить весь CSV в памʼять
🔹 3. Потоковий запис результату в файл
function streamCsvRows(iterable $data): Generator
{
foreach ($data as $row) {
yield implode(',', $row) . "\n";
}
}
header('Content-Type: text/csv');
foreach (streamCsvRows($repository->getLargeDataset()) as $line) {
echo $line;
flush();
}
⚙️ відправка великих звітів чи експорту — без буферизації, у реальному часі.
🔹 4. Поступове завантаження з API
function fetchPages(ApiClient $client): Generator
{
$page = 1;
do {
$data = $client->getPage($page++);
yield from $data['items'];
} while ($data['has_more']);
}
⚡️ ідеально для стрімінгової обробки даних без буферизації
🔹 5. Обхід великої файлової структури
function scanDirRecursive(string $path): Generator
{
foreach (scandir($path) as $item) {
if ($item === '.' || $item === '..') continue;
$full = "$path/$item";
if (is_dir($full)) {
yield from scanDirRecursive($full);
} else {
yield $full;
}
}
}
foreach (scanDirRecursive('/var/log') as $file) {
echo $file . PHP_EOL;
}
📁 ідеально для обходу каталогів, навіть якщо їх тисячі
🧭 Висновок
Генератори — це інструмент не для зручності, а для ефективності.
Вони не дають можливості перемотати чи дізнатись розмір, але саме тому й дозволяють працювати з необмеженими потоками даних.
🔥 Якщо ти колись писав скрипт, який падав через out of memory, —
yield твій новий друг.———
⬅️ Стрілкові функції | DateTimeImmutable ➡️
👍6👏2
Anonymous Quiz
5%
11
5%
12
28%
56
34%
57
17%
67
12%
Помилка
🔥4👍1
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 5/10
⏳ DateTimeImmutable
🧊 Коли час змінюється, а обʼєкти ні
📦 Додано у версії: PHP 5.5
💡 Що дає: клас, який поводиться як
🧠 В чому суть
У PHP якщо ми зробимо зміни часу у обʼєкта
⚙️ Коли це справді має сенс
— у DTO / Value Object — щоб час гарантовано не змінювався після передачі;
— у планувальниках, розкладах, звітах — коли ти рахуєш багато дат від базової;
— у бізнес-логіці — коли з однієї дати обчислюється інша (початок/кінець періоду, дедлайн, акція, тощо).
⚙️ Проблема, яку можна не помітити
У продакшн-коді
І тут трапляється типова історія:
Ми очікували, що початок буде 1 жовтня, але
Той самий код, але з
🧱 Додатковий приклад
Жодних несподіваних мутацій — об’єкт можна безпечно кешувати чи передавати далі.
🧭 Висновок
🔥 Якщо твоя дата здатна змінитись — вона рано чи пізно зламає щось у звіті, логіці або фінансах.
———
⬅️ Генератори | Іменовані аргументи ➡️
🚀 Чи знаєш ти, що PHP так вміє? 5/10
⏳ DateTimeImmutable
🧊 Коли час змінюється, а обʼєкти ні
📦 Додано у версії: PHP 5.5
💡 Що дає: клас, який поводиться як
DateTime, але не змінюється при модифікації, а повертає клонований обʼєкт. 🧠 В чому суть
У PHP якщо ми зробимо зміни часу у обʼєкта
DateTime, він змінився всюди, де передавався, бо обʼєкти в PHP завжди передаються по посиланню, і така поведінка може призвести до неочікуваної поведінки.DateTimeImmutable вирішує цю проблему — будь-яка дія над датою повертає новий екземпляр, а не мутує старий.⚙️ Коли це справді має сенс
— у DTO / Value Object — щоб час гарантовано не змінювався після передачі;
— у планувальниках, розкладах, звітах — коли ти рахуєш багато дат від базової;
— у бізнес-логіці — коли з однієї дати обчислюється інша (початок/кінець періоду, дедлайн, акція, тощо).
⚙️ Проблема, яку можна не помітити
У продакшн-коді
DateTime часто передають між сервісами, DTO або кэшують у контейнерах.І тут трапляється типова історія:
class Campaign {
public function __construct(
public string $name,
public DateTime $startsAt,
public DateTime $endsAt,
) {}
}
$base = new DateTime('2025-10-01');
$campaign = new Campaign(
name: 'Autumn Sale',
startsAt: $base,
endsAt: $base->modify('+7 days')
);
echo $campaign->startsAt->format('Y-m-d'); // 2025-10-08 ❌
echo $campaign->endsAt->format('Y-m-d'); // 2025-10-08Ми очікували, що початок буде 1 жовтня, але
$base мутував під час modify, як наслідок — початок і кінець однакові.Той самий код, але з
DateTimeImmutable працює корректно$base = new DateTimeImmutable('2025-10-01');
$campaign = new Campaign(
name: 'Autumn Sale',
startsAt: $base,
endsAt: $base->modify('+7 days')
);
echo $campaign->startsAt->format('Y-m-d'); // 2025-10-01 ✅
echo $campaign->endsAt->format('Y-m-d'); // 2025-10-08🧱 Додатковий приклад
class Period {
public function __construct(
public DateTimeImmutable $from,
public DateTimeImmutable $to
) {}
public function days(): int {
return $this->to->diff($this->from)->days;
}
}
$period = new Period(
from: $from = new DateTimeImmutable('2025-06-01'),
to: $from->modify('+10 days'),
);
echo $period->days(); // 10Жодних несподіваних мутацій — об’єкт можна безпечно кешувати чи передавати далі.
🧭 Висновок
DateTimeImmutable — це безпечний вибір для роботи з логікою часу.
Він виключає випадкові зміни дат, коли одна змінна призводить до неочікуваних результатів.
🔥 Якщо твоя дата здатна змінитись — вона рано чи пізно зламає щось у звіті, логіці або фінансах.
Immutable цього не дозволить.———
⬅️ Генератори | Іменовані аргументи ➡️
👍7🤝2
Anonymous Quiz
52%
0
42%
1
0%
true
2%
false
4%
null
0%
Помилка
❤2
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 6/10
🧭 Іменовані аргументи
📬 Послідовність більше не має значення
📦 Додано у версії: PHP 8.0
💡 Що дає: можливість передавати аргументи в функції і методи, вказуючи їх імена, а не лише значення.
🧠 В чому суть
До PHP 8 доводилось або пам’ятати точну послідовність аргументів, або постійно підглядати в сігнатуру методу щоб не помилитися який параметр йде за яким. Або в разі, якщо потрібно передати останній з кількох необовʼязкових параметрів, доводилося передавати всі.
З іменованими аргументами можна передавати тільки потрібні параметри — за іменем та ще й в будь-якому порядку.
⚙️ Переваги
— код стає більш самодокументованим — видно, що означає кожен аргумент;
— не треба передавати кіпу непотрібних параметрів лише щоб змінити останній;
— менше ризику переплутати порядок;
— легше рефакторити код — старі виклики не ламаються, якщо змінено послідовність параметрів.
🧱 Реальні приклади
✅ Решта параметрів беруться з дефолтів, і код читається як специфікація виклику методу.
🔹 Приклад із фреймворку (Symfony)
Порядок аргументів не має значення, головне — зрозуміло, що ти задаєш.
🔹 Виклик API або SDK
Кожен аргумент одразу видно без коментарів і документації.
🧭 Висновок
🔥 Якщо функція має більше трьох параметрів — ти знаєш що робити.
———
⬅️ DateTimeImmutable | Enums ➡️
🚀 Чи знаєш ти, що PHP так вміє? 6/10
🧭 Іменовані аргументи
📬 Послідовність більше не має значення
📦 Додано у версії: PHP 8.0
💡 Що дає: можливість передавати аргументи в функції і методи, вказуючи їх імена, а не лише значення.
🧠 В чому суть
До PHP 8 доводилось або пам’ятати точну послідовність аргументів, або постійно підглядати в сігнатуру методу щоб не помилитися який параметр йде за яким. Або в разі, якщо потрібно передати останній з кількох необовʼязкових параметрів, доводилося передавати всі.
З іменованими аргументами можна передавати тільки потрібні параметри — за іменем та ще й в будь-якому порядку.
⚙️ Переваги
— код стає більш самодокументованим — видно, що означає кожен аргумент;
— не треба передавати кіпу непотрібних параметрів лише щоб змінити останній;
— менше ризику переплутати порядок;
— легше рефакторити код — старі виклики не ламаються, якщо змінено послідовність параметрів.
🧱 Реальні приклади
function subscribe(
string $email,
?string $name = null,
?string $language = 'uk',
bool $doubleOptIn = true,
?string $source = null,
?string $tag = null,
bool $sendWelcomeLetter = true,
)
{ /* ... */ }
// до 8.0 треба передати всі, навіть непотрібні ❌
subscribe('alex@example.com', null, 'uk', true, null, null, false);
// після 8.0 можна обмежитися потрібними ✅
createReport('alex@example.com', sendWelcomeLetter: false);
// або навіть передати аргументи в довільному порядку
createReport('alex@example.com', sendWelcomeLetter: false, tag: 'promo2025');
✅ Решта параметрів беруться з дефолтів, і код читається як специфікація виклику методу.
🔹 Приклад із фреймворку (Symfony)
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
{ /* ... */ }
//....
return $this->redirectToRoute(
route: 'user.profile',
status: 301,
parameters: ['id' => $user->getId()]
);
Порядок аргументів не має значення, головне — зрозуміло, що ти задаєш.
⚠️ Варто зазначити, що не треба без необхідності змінювати порядок аргументів лише тому, що PHP це дозволяє. Якщо бачиш в коді такі місця — краще відрефактор їх і поверни природну послідовність параметрів.
IDE, наприклад PhpStorm, зазвичай підсвічує такі виклики не дарма — це підказка, що час навести лад.
🔹 Виклик API або SDK
$client->sendMessage(
to: '380501234567',
text: 'Привіт 👋',
channel: ChannelsEnum::TELEGRAM,
);
Кожен аргумент одразу видно без коментарів і документації.
🧭 Висновок
Іменовані аргументи — це конфігураційний стиль виклику функцій, який робить код читабельним і безпечним для змін.
Більше не потрібно прокидати кіпу null, щоб дістатися до потрібного параметра.
🔥 Якщо функція має більше трьох параметрів — ти знаєш що робити.
———
⬅️ DateTimeImmutable | Enums ➡️
👍5🔥1
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 7/10
🧱 Enums
🎯 Тилькі цільові значення
📦 Додано у версії: PHP 8.1
💡 Що дає: нативний механізм для створення перелічуваних типів — із чіткими, типізованими значеннями замість "магічних рядків та чисел" і нескінченних const.
❤️ Трохи особистого
Це один із моїх найулюбленіших інструментів у PHP. З моменту їх появи я взагалі не уявляю розробки без enum’ів — вони зменшують кількість помилок, роблять код читабельним і гарантують типобезпеку.
Але спілкування з розробниками показує, що далеко не всі розділяють цей захват. Тому хочу поділитися своєю любов’ю до них і пояснити, чому це не просто "список значень", а справжній крок вперед для PHP.
🧠 Типи enum’ів
PHP має два різновиди enum’ів:
1️⃣ Backed Enum — із базовим значенням (
Кожен
📦 Для чого:
— зручно в статусах замовлень, документів, платежів, типів повідомлень, типів працівників, тощо;
— легко зберігати в базі як звичайний рядок;
— можна отримати enum через
2️⃣ Pure Enum — без бекінгу
Просто набір унікальних case без значень. Використовується тоді, коли значення не потрібне —
важливий сам факт "стану" або "режиму".
📦 Для чого:
— для внутрішніх логічних станів або режимів роботи;
— коли не треба нічого зберігати у БД;
— коли досить просто перевірити
🧩 Більше, ніж просто перелік
Більшість вважає, що
⚙️ Приклад enum із методами
🧱 Інший приклад
Статуси документів, каналів, ролей
🧭 Висновок
❤️ Я вже не уявляю розробки без enum’ів.
І якщо ти досі не використовуєш їх у своїх проєктах — просто спробуй, через тиждень без них ти вже не зможеш писати старим способом.
———
⬅️ Іменовані аргументи | readonly + accessors ➡️
🚀 Чи знаєш ти, що PHP так вміє? 7/10
🧱 Enums
🎯 Тилькі цільові значення
📦 Додано у версії: PHP 8.1
💡 Що дає: нативний механізм для створення перелічуваних типів — із чіткими, типізованими значеннями замість "магічних рядків та чисел" і нескінченних const.
❤️ Трохи особистого
Це один із моїх найулюбленіших інструментів у PHP. З моменту їх появи я взагалі не уявляю розробки без enum’ів — вони зменшують кількість помилок, роблять код читабельним і гарантують типобезпеку.
Але спілкування з розробниками показує, що далеко не всі розділяють цей захват. Тому хочу поділитися своєю любов’ю до них і пояснити, чому це не просто "список значень", а справжній крок вперед для PHP.
🧠 Типи enum’ів
PHP має два різновиди enum’ів:
1️⃣ Backed Enum — із базовим значенням (
string або int)Кожен
case має прив’язане значення, це дозволяє порівнювати його з іншими значеннями, серіалізувати, зберігати його в БД, та при цьому бути впевненним, що значення завжди буде одним з дозволених в переліченні.enum Status: string
{
case DRAFT = 'draft';
case ACTIVE = 'active';
case ARCHIVED = 'archived';
}
📦 Для чого:
— зручно в статусах замовлень, документів, платежів, типів повідомлень, типів працівників, тощо;
— легко зберігати в базі як звичайний рядок;
— можна отримати enum через
Status::from('draft') або безпечно — tryFrom('draft').2️⃣ Pure Enum — без бекінгу
Просто набір унікальних case без значень. Використовується тоді, коли значення не потрібне —
важливий сам факт "стану" або "режиму".
enum Direction
{
case NORTH;
case SOUTH;
case EAST;
case WEST;
}
📦 Для чого:
— для внутрішніх логічних станів або режимів роботи;
— коли не треба нічого зберігати у БД;
— коли досить просто перевірити
if ($direction === Direction::NORTH).🧩 Більше, ніж просто перелік
Більшість вважає, що
enum — це просто заміна const. Насправді це класоподібна конструкція, у якій можна (і треба!) додавати методи, поведінку, статичні методи та перетворення значень.⚙️ Приклад enum із методами
enum Status: string
{
case DRAFT = 'draft';
case ACTIVE = 'active';
case ARCHIVED = 'archived';
// 🔹 Нестатичний метод — для конкретного значення
public function label(): string
{
return match($this) {
self::DRAFT => 'Чернетка',
self::ACTIVE => 'Активна',
self::ARCHIVED => 'Архівована',
};
}
// 🔹 Статичний метод — спільний для всіх
public static function visible(): array
{
return [self::DRAFT, self::ACTIVE];
}
}
echo Status::ACTIVE->label(); // Активна
print_r(Status::visible()); // [Status::DRAFT, Status::ACTIVE]
🧱 Інший приклад
Статуси документів, каналів, ролей
enum Channel: string
{
case EMAIL = 'email';
case SMS = 'sms';
case TELEGRAM = 'telegram';
public function icon(): string
{
return match($this) {
self::EMAIL => '✉️',
self::SMS => '📱',
self::TELEGRAM => '💬',
};
}
public function getSenderFQCN(): string
{
return match($this) {
self::EMAIL => EmailSender::class,
self::SMS => SMSSender::class,
self::TELEGRAM => TelegramSender::class,
};
}
public static function fromString(string $value): ?self
{
return self::tryFrom($value);
}
}
🧭 Висновок
Enum’и — це одне із найвдаліших оновлень в PHP за останні роки.
Вони дисциплінують код, роблять модель даних передбачуваною й забезпечують реальну типобезпеку.
❤️ Я вже не уявляю розробки без enum’ів.
І якщо ти досі не використовуєш їх у своїх проєктах — просто спробуй, через тиждень без них ти вже не зможеш писати старим способом.
———
⬅️ Іменовані аргументи | readonly + accessors ➡️
❤2👍1
#️⃣ #php #doctrine #enum #4students #tips #tools
🧩 Doctrine + Enum
Я так люблю enum’и, що зробив навіть власний пакет — ufo-tech/doctrine-helper, який навчає
1️⃣ Створи свій PHP Enum для поля сутності
2️⃣ Створи власний DBAL-тип і наслідуй Ufo\DoctrineHelper\DBAL\AbstractEnumType
3️⃣ Зареєструй новий тип у Doctrine
4️⃣ Використовуй PHP Enum для зберігання й зміни значення
💡 Таким чином MySQL ENUM поводиться як повноцінний PHP Enum — із типобезпекою, автопідказками IDE та без ручного кастингу.
🧩 Doctrine + Enum
Я так люблю enum’и, що зробив навіть власний пакет — ufo-tech/doctrine-helper, який навчає
Doctrine розуміти enum у типізованих полях сутності і створювати під них ENUM() тип поля в MySQL.1️⃣ Створи свій PHP Enum для поля сутності
<?php
namespace App;
enum MyEnum: string
{
case CASE_1 = 'Мій варіант 1';
case CASE_2 = 'Мій варіант 2';
}
2️⃣ Створи власний DBAL-тип і наслідуй Ufo\DoctrineHelper\DBAL\AbstractEnumType
<?php
namespace App\DBAL;
use BackedEnum;
use App\MyEnum;
class MyEnumType extends AbstractEnumType
{
protected string|BackedEnum $enum = MyEnum::class;
}
3️⃣ Зареєструй новий тип у Doctrine
doctrine:
dbal:
types:
App\MyEnum: 'App\DBAL\MyEnumType'
mapping_types:
enum: string
4️⃣ Використовуй PHP Enum для зберігання й зміни значення
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use App\MyEnum;
#[ORM\Entity]
#[ORM\Table(name: 'demo')]
class Demo
{
#[ORM\Column(type: MyEnum::class, nullable: false)]
protected string $case;
public function __construct(MyEnum $case)
{
$this->case = $case->value;
}
public function changeCase(MyEnum $case): void
{
$this->case = $case->value;
}
public function getCase(): string
{
return $this->case;
}
}
💡 Таким чином MySQL ENUM поводиться як повноцінний PHP Enum — із типобезпекою, автопідказками IDE та без ручного кастингу.
👍3❤1
#holywar #4students #architecture #php
📤 Відповідаю на питання
1. Чи можна використовувати try/catch для управління логікою?
Так, можна, і це цілком робочий підхід. Питання тут не в "правильно/неправильно", а в тому, яка філософія тобі ближча і що підходить під конкретну архітектуру.
Насправді, це дуже холіварна тема.
Є табір, який каже "винятки тільки для виняткових ситуацій", а є табір, який спокійно використовує їх як механізм flow control. І обидва підходи живуть собі нормально.
Я особисто вважаю, що це питання зручності, а не абсолютна істина, мені зручніше обʼєктно-орієнтований підхід, ІМХО якщо код читається краще — значить підхід має право на життя.
Приклад:
У такій ситуації це працює природно і зрозуміло: "немає? створи". Немає нічого поганого в тому, щоб ловити конкретний виняток і робити fallback-логіку.
Проблеми починаються тільки тоді, коли exception використовується замість звичайного if у найпростіших місцях, або коли репозиторій починає кидати винятки там, де очікувано повертати null. Але то вже питання дизайну коду.
2. Чи дійсно throw дорогий?
Так, це правда.
try/catch сам по собі майже нічого не коштує. Їх можна хоч вкладати — накладні витрати мізерні, але throw — дорогий, бо PHP генерує backtrace і створює повноцінний Exception-об’єкт, що виїдає процесор.
Тому:
— Якщо
— Якщо "not found" стає нормальним шляхом виконання (часто), тоді варто задуматись, чи не простіше повертати null або Result-об’єкт — чисто з точки зору продуктивності.
Але й тут все залежить від контексту. Якщо загрузка невелика — різниця взагалі не має сенсу.
Підсумую мою позицію
— Використовувати try/catch для логіки можна. Це не є поганою практикою само по собі, це питання смаку, стилю і команди.
— Якщо код читається краще — я завжди за.
— try/catch дешевий, throw дорожчий, але в реальних проєктах це рідко стає bottleneck’ом.
Якщо тобі це зручно і воно вписується в архітектуру — продовжуй використовувати.
———
Чекаю холіварників у коментах
📤 Відповідаю на питання
Саша привіт! Потрібна твоя консультація. Скажи, будь ласка:
1. чи можна використовувати try catch для управління логікою? Я досі використовував, але сьогодні натрапив на твердження, що це не є хороша практика.
2. Наскільки ресурсозатратне використання вкладених try catch? Прочитав, що сам try catch сам по собі "дешевий", а от throw вимагає багато ресурсів. Це так?
Наперед дякую
1. Чи можна використовувати try/catch для управління логікою?
Так, можна, і це цілком робочий підхід. Питання тут не в "правильно/неправильно", а в тому, яка філософія тобі ближча і що підходить під конкретну архітектуру.
Насправді, це дуже холіварна тема.
Є табір, який каже "винятки тільки для виняткових ситуацій", а є табір, який спокійно використовує їх як механізм flow control. І обидва підходи живуть собі нормально.
Я особисто вважаю, що це питання зручності, а не абсолютна істина, мені зручніше обʼєктно-орієнтований підхід, ІМХО якщо код читається краще — значить підхід має право на життя.
Приклад:
try {
$code = $repo->getByUrl($url);
} catch (NotFoundException) {
$code = $this->generateAndSave($url);
}У такій ситуації це працює природно і зрозуміло: "немає? створи". Немає нічого поганого в тому, щоб ловити конкретний виняток і робити fallback-логіку.
Проблеми починаються тільки тоді, коли exception використовується замість звичайного if у найпростіших місцях, або коли репозиторій починає кидати винятки там, де очікувано повертати null. Але то вже питання дизайну коду.
2. Чи дійсно throw дорогий?
Так, це правда.
try/catch сам по собі майже нічого не коштує. Їх можна хоч вкладати — накладні витрати мізерні, але throw — дорогий, бо PHP генерує backtrace і створює повноцінний Exception-об’єкт, що виїдає процесор.
Тому:
— Якщо
throw трапляється рідко — взагалі не проблема.— Якщо "not found" стає нормальним шляхом виконання (часто), тоді варто задуматись, чи не простіше повертати null або Result-об’єкт — чисто з точки зору продуктивності.
Але й тут все залежить від контексту. Якщо загрузка невелика — різниця взагалі не має сенсу.
Підсумую мою позицію
— Використовувати try/catch для логіки можна. Це не є поганою практикою само по собі, це питання смаку, стилю і команди.
— Якщо код читається краще — я завжди за.
— try/catch дешевий, throw дорожчий, але в реальних проєктах це рідко стає bottleneck’ом.
Якщо тобі це зручно і воно вписується в архітектуру — продовжуй використовувати.
———
Чекаю холіварників у коментах
👍11🔥2👎1
Про продовження циклу "Чи знаєш ти, що PHP так вміє?" не забув, просто наразі не маю часу 😒
👌9❤1
🎉 DOU PHP Meetup — Чорна пʼятниця на DOU
Цього року мене запрошували доповідати на DOU PHP Meetup, але, на жаль, не вийшло поїхати — домовилися перенести мій виступ на наступний рік.
А поки — ловіть знижку, якщо хочете приєднатись цього року.
💥 Акція 1+1: купуєш квиток — другий прилітає на пошту безкоштовно.
🕺 Акція діє з 27.11 до 30.11
🎫 Якщо йдеш сам — тримай -15%:
👉 https://dou.ua/goto/RK7i
Хто піде — напишіть в коментах, цікаво хто там буде ✌️
Цього року мене запрошували доповідати на DOU PHP Meetup, але, на жаль, не вийшло поїхати — домовилися перенести мій виступ на наступний рік.
А поки — ловіть знижку, якщо хочете приєднатись цього року.
💥 Акція 1+1: купуєш квиток — другий прилітає на пошту безкоштовно.
🕺 Акція діє з 27.11 до 30.11
🎫 Якщо йдеш сам — тримай -15%:
FROM_DOCTOR_15 (акції не комбінуються)👉 https://dou.ua/goto/RK7i
Хто піде — напишіть в коментах, цікаво хто там буде ✌️
🔥3
#sql #course #4students
Обіцяю, це останній пост про Чорну пʼятницю 😅
Але гріх не поділитись, якщо вже зробили -50% на мій курс по MySQL для Hillel Max.
Курс короткий, без води, лише практичні речі, які реально потрібні девелоперам.
Чорна пʼятниця — нормальний момент почати те, що відкладали місяцями 😉
А якщо ще вагаєшся, то спробуй безкоштовні пробні заняття:
— на Hillel Max
— на моєму YouTube
Хто проходив — можете відписати, чи було корисно 🖤
Обіцяю, це останній пост про Чорну пʼятницю 😅
Але гріх не поділитись, якщо вже зробили -50% на мій курс по MySQL для Hillel Max.
Курс короткий, без води, лише практичні речі, які реально потрібні девелоперам.
Чорна пʼятниця — нормальний момент почати те, що відкладали місяцями 😉
А якщо ще вагаєшся, то спробуй безкоштовні пробні заняття:
— на Hillel Max
— на моєму YouTube
Хто проходив — можете відписати, чи було корисно 🖤
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 8/10
🔒 readonly + accessors
🧱 Стабільні DTO і Value Object без бойлерплейту
📦 Додано у версіях:
readonly — PHP 8.1
accessors — PHP 8.4
💡 Що це дає: можливість створювати об’єкти, дані в яких неможливо змінити випадково,
та новий синтаксис контролю доступу до властивостей через get / set без окремих методів.
🧠 В чому суть:
значення можна встановити лише один раз (зазвичай у конструкторі).
без класичних геттерів і сеттерів — прямо в тілі класу.
Разом вони створюють ідеальну комбінацію для DTO, VO і конфігураційних класів:
дані незмінні, а доступ контрольований.
🧱 Приклад класичного підходу
✅ працює, але більша частина коду тут тільки заради забезпечення базової інкапсуляції.
⚡️ Тепер те саме — сучасно
Ще приклад — Value Object
👌 Ніяких змін після створення, тільки контрольований доступ при читанні.
⚙️ Де це реально корисно
🔹
🔹
🧭 Висновок
🔥 Сьогодні кожен мій DTO — readonly.
———
⬅️ Enums | Атрибути ➡️
🚀 Чи знаєш ти, що PHP так вміє? 8/10
🔒 readonly + accessors
🧱 Стабільні DTO і Value Object без бойлерплейту
📦 Додано у версіях:
readonly — PHP 8.1
accessors — PHP 8.4
💡 Що це дає: можливість створювати об’єкти, дані в яких неможливо змінити випадково,
та новий синтаксис контролю доступу до властивостей через get / set без окремих методів.
🧠 В чому суть:
readonly робить властивість незмінною після ініціалізації —значення можна встановити лише один раз (зазвичай у конструкторі).
accessors дозволяють додати контроль при читанні та записі властивостейбез класичних геттерів і сеттерів — прямо в тілі класу.
Разом вони створюють ідеальну комбінацію для DTO, VO і конфігураційних класів:
дані незмінні, а доступ контрольований.
🧱 Приклад класичного підходу
class Product {
private string $name;
private float $price;
public function __construct(string $name, float $price)
{
$this->name = $name;
$this->price = $price;
}
public function getPrice(): float {
return $this->price;
}
public function setPrice(float $price): void {
if ($price < 0) {
throw new InvalidArgumentException('Price must be positive');
}
$this->price = $price;
}
}✅ працює, але більша частина коду тут тільки заради забезпечення базової інкапсуляції.
⚡️ Тепер те саме — сучасно
class Product {
public readonly string $name;
private float $price {
get => $this->price;
set => $this->price = max(0, $value);
}
public function __construct(string $name, float $price)
{
$this->name = $name;
$this->price = $price;
}
}readonly гарантує незмінність імені,accessors автоматично перевіряють ціну при записі.Ще приклад — Value Object
class Coordinates {
public readonly float $lat {
get => round($this->lat, 6);
}
public readonly float $lng {
get => round($this->lng, 6);
}
public function __construct(float $lat, float $lng)
{
$this->lat = $lat;
$this->lng = $lng;
}
}👌 Ніяких змін після створення, тільки контрольований доступ при читанні.
⚙️ Де це реально корисно
🔹DTO: запити й відповіді в API;🔹
Value Object: Money, Price, GeoPoint, Range;🔹
Immutable конфігурації: параметри сервісів, константні стани.🧭 Висновок
readonly і accessors — це крок до справжніх record-класів у PHP.
Вони дозволяють писати чисті, передбачувані структури без тонни бойлерплейту.
🔥 Сьогодні кожен мій DTO — readonly.
———
⬅️ Enums | Атрибути ➡️
👍1
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 9/10
🏷 Атрибути
✨ Метапрограмування без DocBlock-хаків
📦 Додано у версії: PHP 8.0
💡 Що дає: нативний, типобезпечний механізм додавання метаданих до класів, методів, властивостей та параметрів — без необхідності при їх читанні парсити DocBlock-и та встановлювати сторонні бібліотеки.
❤️ Трохи особистого
До PHP 8.0 в мене був один технічний “біль”, про який знають тільки ті, хто коли-небудь пробував будувати API-документацію чи SDK на основі читання коду.
Скажу лише одне: парсинг DocBlock-ів — це дуже невдячна робота.
Атрибути стали тією фічею, після якої мої бібліотеки буквально отримали "вдих свіжого повітря".
Код став чистішим, простішим, а метадані — нарешті передбачуваними.
🧩 Навіщо вони взагалі потрібні?
До PHP 8 метадані доводилося писати так:
Це був просто коментар, який не розбирається стандартними засобами PHP такими як рефлексія. Для аналізу потрібна ще одна бібліотека-парсер, яка мала вгадати, що розробник мав на увазі.
Атрибути роблять метакоментарі типізованими, тепер вони обʼєктні:
Це буквально декларація єкземпляру класів Route та SomeFlag і IDE точно знає, що всередині. Це дає:
— нативне використання
— розуміння які параметри треба передати
— легке читання коду
— легке використання цих даних
🧱 Приклади застосування
1️⃣ Доктрина
2️⃣ Symfony Routing
3️⃣ Валідація
4️⃣ Кастомні аттрибути
🧠 А що можна робити з атрибутами?
Майже все, що роблять Java/Spring- або C#-атрибути:
🔹позначати класи й методи
🔹додавати метадані
🔹створювати власні декларативні правила
🔹будувати роутинг
🔹маркувати серіалізацію/десеріалізацію
🔹автоматизувати DI/автовіринг
🔹вказувати, як працює кешування чи логування
🔹створювати декларативні контракти для DTO
Фактично — інструмент, щоб писати менше імперативного коду та більше декларативного.
✨ Як створити власний атрибут
Використання:
🔍 Як прочитати атрибут через Reflection
📌 Особливо важливо
🔹атрибути це повноцінний об’єкт, а не просто рядок в коментарі
🔹вони мають простір імен
🔹можна типізувати параметри
🔹можна використовувати передові конструкції (enum, readonly, VO)
🔹ідеально комбінуються з DI-контейнерами
🧭 Висновок
———
⬅️ readonly + accessors
🚀 Чи знаєш ти, що PHP так вміє? 9/10
🏷 Атрибути
✨ Метапрограмування без DocBlock-хаків
📦 Додано у версії: PHP 8.0
💡 Що дає: нативний, типобезпечний механізм додавання метаданих до класів, методів, властивостей та параметрів — без необхідності при їх читанні парсити DocBlock-и та встановлювати сторонні бібліотеки.
❤️ Трохи особистого
До PHP 8.0 в мене був один технічний “біль”, про який знають тільки ті, хто коли-небудь пробував будувати API-документацію чи SDK на основі читання коду.
Скажу лише одне: парсинг DocBlock-ів — це дуже невдячна робота.
Атрибути стали тією фічею, після якої мої бібліотеки буквально отримали "вдих свіжого повітря".
Код став чистішим, простішим, а метадані — нарешті передбачуваними.
🧩 Навіщо вони взагалі потрібні?
До PHP 8 метадані доводилося писати так:
/**
* @Route("/users")
* @SomeFlag(true)
*/
class UserController {}
Це був просто коментар, який не розбирається стандартними засобами PHP такими як рефлексія. Для аналізу потрібна ще одна бібліотека-парсер, яка мала вгадати, що розробник мав на увазі.
Атрибути роблять метакоментарі типізованими, тепер вони обʼєктні:
#[Route('/users')]
#[SomeFlag(true)]
class UserController {}Це буквально декларація єкземпляру класів Route та SomeFlag і IDE точно знає, що всередині. Це дає:
— нативне використання
— розуміння які параметри треба передати
— легке читання коду
— легке використання цих даних
🧱 Приклади застосування
1️⃣ Доктрина
#[ORM\Entity]
class Product
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
public int $id;
#[ORM\Column(length: 255)]
public string $name;
}
2️⃣ Symfony Routing
#[Route('/orders/{id}', methods: ['GET'])]
public function show(int $id) { ... }3️⃣ Валідація
class RegistrationDTO
{
#[Assert\Email]
#[Assert\NotBlank]
public string $email;
#[Assert\Length(min: 8)]
public string $password;
}
4️⃣ Кастомні аттрибути
#[API\Method('user.create')]
class CreateUserRequest
{
#[API\Param]
public string $email;
#[API\Param]
public string $password;
}🧠 А що можна робити з атрибутами?
Майже все, що роблять Java/Spring- або C#-атрибути:
🔹позначати класи й методи
🔹додавати метадані
🔹створювати власні декларативні правила
🔹будувати роутинг
🔹маркувати серіалізацію/десеріалізацію
🔹автоматизувати DI/автовіринг
🔹вказувати, як працює кешування чи логування
🔹створювати декларативні контракти для DTO
Фактично — інструмент, щоб писати менше імперативного коду та більше декларативного.
✨ Як створити власний атрибут
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class Loggable
{
public function __construct(
public string $message = 'default',
public bool $enabled = true,
) {}
}
Використання:
#[Loggable(message: 'Auth attempt')]
class AuthService {}
🔍 Як прочитати атрибут через Reflection
$ref = new ReflectionClass(AuthService::class);
$attrs = $ref->getAttributes(Loggable::class);
$instance = $attrs[0]->newInstance();
echo $instance->message;
📌 Особливо важливо
🔹атрибути це повноцінний об’єкт, а не просто рядок в коментарі
🔹вони мають простір імен
🔹можна типізувати параметри
🔹можна використовувати передові конструкції (enum, readonly, VO)
🔹ідеально комбінуються з DI-контейнерами
🧭 Висновок
Атрибути — це одна з тих фіч, після яких старий PHP здається архаїчним.
Типобезпека, декларативність, прозора робота через Reflection, відсутність DocBlock-магії — це все робить їх інструментом, який я обожнюю використовувати у власних бібліотеках.
Це настільки природно, що важко повірити, що колись ми писали метадані в коментарях.
———
⬅️ readonly + accessors
👍14