Перелік хештегів для зручного пошуку постів
📚 Тематика
#php
#architecture
#symfony
#composer
#docker
#sql
#testing
#designpatterns
#solid
#oop
#ddd
#jsonrpc
#microservices
#documentations
#algorithm
🛠 Практика
#examples — корисне
#tools — інструменти, утиліти
#tips — короткі поради
#mistakes — типові граблі
#refactor — приклади рефакторингу
#debug — про дебаг, логування, профілювання
#phpstorm — найкраща IDE
#ai — ШІ помічник
👨🏫 Освіта / досвід
#videoarchive — архівне відео з (вебінарів)
#course — матеріали з курсів
#question — питання до аудиторії
#talks — думки й міркування
#4students — для випускників
😄 Гумор і факапи
#game — інтерактивна гра
#rants — бурчання з досвідом
#wtf — код або ситуації, від яких немає слів
#humor — ІТ гумор
#quote — цитати від студентів і колег
Інше
#longread
#holywar
#rating
#career
#work
#series — серія статей
UPD:
В коментарях під цим постом можна писати запити на теми, що вас цікавлять
📚 Тематика
#php
#architecture
#symfony
#composer
#docker
#sql
#testing
#designpatterns
#solid
#oop
#ddd
#jsonrpc
#microservices
#documentations
#algorithm
🛠 Практика
#examples — корисне
#tools — інструменти, утиліти
#tips — короткі поради
#mistakes — типові граблі
#refactor — приклади рефакторингу
#debug — про дебаг, логування, профілювання
#phpstorm — найкраща IDE
#ai — ШІ помічник
👨🏫 Освіта / досвід
#videoarchive — архівне відео з (вебінарів)
#course — матеріали з курсів
#question — питання до аудиторії
#talks — думки й міркування
#4students — для випускників
😄 Гумор і факапи
#game — інтерактивна гра
#rants — бурчання з досвідом
#wtf — код або ситуації, від яких немає слів
#humor — ІТ гумор
#quote — цитати від студентів і колег
Інше
#longread
#holywar
#rating
#career
#work
#series — серія статей
UPD:
В коментарях під цим постом можна писати запити на теми, що вас цікавлять
🔥3👍2
#course #php #longread
match !== switch
Вже відносно давно — починаючи з PHP 8.0 (а це вже 1,5 роки тому 😳) — зʼявився новий інструмент:
❗️Але це не так.
Сьогодні я спробую пояснити, чому match — це окремий інструмент із своїми перевагами і призначенням.
1️⃣ match повертає значення 🔄
2️⃣ Обовʼязкове покриття всіх кейсів ✅
У
3️⃣ Завжди суворе порівняння (===), а не вільне (==) 🧠
У
☝️
4️⃣ Немає fallthrough і break 🧱
У
Хто не знає про що мова, просто виконайте цей код:
5️⃣ Виховує декларативність ✨
6️⃣ Продуктивність: O(1) доступ по значенню ⚡️
———
Висновки 🎯
❗️Якщо ти ще не використовуєш
Як кажуть: "Відчуй різницю" 😉
match !== switch
Вже відносно давно — починаючи з PHP 8.0 (а це вже 1,5 роки тому 😳) — зʼявився новий інструмент:
match. Але практика співбесід (як джунів, так і мідлів) показує, що багато хто, в кращому випадку, просто знає про нього, але не використовує у повсякденному коді. Основна причина — поверхневе розуміння: існує думка, що це просто ще один синтаксичний цукор над switch чи if/else. ❗️Але це не так.
Сьогодні я спробую пояснити, чому match — це окремий інструмент із своїми перевагами і призначенням.
1️⃣ match повертає значення 🔄
match — це вираз, а не інструкція. Він завжди повертає результат, який потрібно привласнити змінній:$taxRate = match($countryCode) {
'UA' => 0.20,
'PL' => 0.23,
'DE' => 0.19,
default => 0.0,
};switch та if/else, на відміну від цього, нічого не повертають. Якщо ви хочете отримати результат — доводиться оголошувати змінну перед умовою, потім в кожному кейсі встановлювати їй значення.2️⃣ Обовʼязкове покриття всіх кейсів ✅
match зобовʼязує розробника обробити всі можливі варіанти або вказати default. Якщо не вказано відповідність — буде UnhandledMatchError. Це значно знижує ризики неочевидних помилок.$action = match($input) {
'start' => 'Запуск',
'stop' => 'Зупинка',
default => 'Пауза',
};У
switch та if/else будь-який відсутній case просто проігнорується.3️⃣ Завжди суворе порівняння (===), а не вільне (==) 🧠
У
match значення порівнюються суворо — без приведення типів. Це ще один реверанс php в бік суворої типізації і плюс до безпеки та передбачуваності:match(0) {
false => 'false', // ❌ UnhandledMatchError
0 => 'zero', // ✅ буде виконано
};
switch (0) {
case false:
echo 'false'; // ✅ буде виведено
break;
case 0:
echo 'zero'; // ❌ сюди не дійде
break;
}☝️
switch у цьому випадку вибере false як відповідність до 0, що може призвести до неочікуваної поведінки.4️⃣ Немає fallthrough і break 🧱
У
switch завжди є ризик забути break, і тоді код "провалиться" в наступний кейс. Це класичне джерело помилок. У match кожен кейс — це окреме правило, і немає поняття break чи переходу до наступного.Хто не знає про що мова, просто виконайте цей код:
$value = 2;
switch ($value) {
case 1:
echo 'one';
case 2:
echo 'two';
case 3:
echo 'three';
}
5️⃣ Виховує декларативність ✨
match заохочує до декларативного стилю — без зайвої логіки в тілі конструкції. Він не дозволяє писати довгі блоки коду в кожному кейсі, лише вирази. Це змушує структурувати код краще:return match(true) {
$x > 0 => 'позитивне',
$x < 0 => 'негативне',
default => 'нуль',
};6️⃣ Продуктивність: O(1) доступ по значенню ⚡️
match працює аналогічно хеш-мапі: якщо йдеться про скалярні значення (int, float, string, bool), він здійснює пошук у константний час — по складності алгоритму O(1). Це дає велику перевагу над switch, де кожен case порівнюється послідовно (складність алгоритму O(n)):// match — O(1):
$color = match($code) {
'R' => 'Red',
'G' => 'Green',
'B' => 'Blue',
default => 'Unknown',
};
// switch — O(n):
switch ($code) {
case 'R': $color = 'Red'; break;
case 'G': $color = 'Green'; break;
case 'B': $color = 'Blue'; break;
default: $color = 'Unknown';
}
———
Висновки 🎯
match — це не альтернатива switch чи if/else, а окремий інструмент для ситуацій, де важлива чіткість та суворість, тобто для всіх ситуацій з умовами
Він допомагає уникати класичних помилок з switch і заохочує до чистішого, передбачуваного коду
Він швидкий: прості значення шукаються у константний час.
❗️Якщо ти ще не використовуєш
match у повсякденній роботі, саме час спробувати його у своїй наступній задачі. Як кажуть: "Відчуй різницю" 😉
🔥12👌4👍1
#course #php #php8_5 #talks #4students
А хіба current() та end() вже не справляються❓
На одній з персональних консультацій ми з одним з підписників обговорювали статтю про нововведення в PHP 8.5, зокрема появу функцій
У нього виникло питання:
І раптом я подумав, що це питання може виникнути не тільки в нього, бо може здатися, що
Тому я вирішив написати короткий пост, щоб розкласти все по поличках 👇
Функції
Тобто функція
Концептуальний приклад:
Ми хочемо вивести всі елементи масиву, якщо останній елемент не "d"
Але на екран виведеться тильки 'c'
✅
Нові функції будуть завжди повертати перше або останнє значення без побічних ефектів.
Вони не змінюють стан вказівника і не залежать від нього:
📌 PHP продовжує розвиватися в бік декларативного і безпечного коду, і ці нові функції — це не "зайве", а ще один крок до меншої кількості багів.
Якщо помітили у себе в коді
А хіба current() та end() вже не справляються❓
На одній з персональних консультацій ми з одним з підписників обговорювали статтю про нововведення в PHP 8.5, зокрема появу функцій
array_first() та array_last().У нього виникло питання:
“А навіщо це потрібно, якщо є current() і end()?”
І раптом я подумав, що це питання може виникнути не тільки в нього, бо може здатися, що
current() та end() роблять те саме.Тому я вирішив написати короткий пост, щоб розкласти все по поличках 👇
Функції
current() справді повертає перший елемент, а end() останній елемент масиву, але тільки після того, як зрушують внутрішній вказівник масиву. Це означає, що:$array = ['a', 'b', 'c', 'd'];
echo current($array); // 'a'
echo next($array); // 'b'
echo current($array); // 'b', а не 'a'
echo end($array); // 'd'
echo current($array); // 'd' а не 'a'
Тобто функція
current() повертає не перший елемент масиву, а той, на який вказує вказівник, а end() останній елемент масиву, але при цьому переставляє на нього внутрішній вказівник масиву, що в свою чергу може привезти до непередбачуванних наслідків.Концептуальний приклад:
Ми хочемо вивести всі елементи масиву, якщо останній елемент не "d"
$array = ['a', 'b', 'c'];
if (end($array) !== 'd') { // але вказівник вже перемістився на 'c'
while ($item = current($array)) {
echo $item . PHP_EOL;
next($array);
}
}
Але на екран виведеться тильки 'c'
✅
array_first() та array_last() — декларативні та передбачуваніНові функції будуть завжди повертати перше або останнє значення без побічних ефектів.
Вони не змінюють стан вказівника і не залежать від нього:
$array = ['a', 'b', 'c'];
array_first($array); // 'a'
array_last($array); // 'c'
// Незалежно від вказівника
next($array);
array_first($array); // все ще 'a'
📌 PHP продовжує розвиватися в бік декларативного і безпечного коду, і ці нові функції — це не "зайве", а ще один крок до меншої кількості багів.
Якщо помітили у себе в коді
current() чи end() — можливо, час подивитись на них під новим кутом.SensioLabs
What's New in PHP 8.5: A Comprehensive Overview
PHP 8.5 will be released in November 2025 and brings several useful new features and improvements. This version focuses on developer experience enhancements, new utility functions, and better debug...
❤5👍4
#course #php #talks #4students #tips #tools
🧲 Один з інструментів DRY або єдиний дозволений copy/paste
Багато технічних співбесід показують, що розробники або не використовують трейти зовсім, або роблять це без розуміння практичного сенсу. Часто їх просто бояться — мовляв, поведінка трейту може бути неочевидною або ж спричинити баги, які складно відслідкувати.
Але суть в тому, що трейти — це всього лише інструмент, який треба застосовувати там, де від нього буде найбільше користі.
І найчастіше це не сервісні класи (хоча є ситуації коли і тут вони будуть доречні), а обʼєктні структури: сутності, DTO, VO, event'и тощо. Саме там трейти — ідеальний інструмент для роздачі типової поведінки без зайвої ієрархії і порушення
Гарний приклад — бібліотека knplabs/doctrine-behaviors. своїми інтерфейсами вона надає вашим сутностям типову поведінку (наприклад, Timestampable, SoftDeletable, Translatable тощо), але замість того, щоб реалізовувати інтерфейси в кожному класі, ви просто додаєте реалізацію — підключаючи відповідний трейт. Ніяких милиць у вигляді абстрактних батьківських класів, які «надають поведінку», тільки чистий код, лаконічний
Хоча справедливості заради варто визнати:
🎯 Висновок
PS:
🧠 Порада: як зробити, щоб трейт гарантовано працював в будь-якому класі без помилок?
Погано:
Добре:
🧲 Один з інструментів DRY або єдиний дозволений copy/paste
Багато технічних співбесід показують, що розробники або не використовують трейти зовсім, або роблять це без розуміння практичного сенсу. Часто їх просто бояться — мовляв, поведінка трейту може бути неочевидною або ж спричинити баги, які складно відслідкувати.
Але суть в тому, що трейти — це всього лише інструмент, який треба застосовувати там, де від нього буде найбільше користі.
І найчастіше це не сервісні класи (хоча є ситуації коли і тут вони будуть доречні), а обʼєктні структури: сутності, DTO, VO, event'и тощо. Саме там трейти — ідеальний інструмент для роздачі типової поведінки без зайвої ієрархії і порушення
DRY.Гарний приклад — бібліотека knplabs/doctrine-behaviors. своїми інтерфейсами вона надає вашим сутностям типову поведінку (наприклад, Timestampable, SoftDeletable, Translatable тощо), але замість того, щоб реалізовувати інтерфейси в кожному класі, ви просто додаєте реалізацію — підключаючи відповідний трейт. Ніяких милиць у вигляді абстрактних батьківських класів, які «надають поведінку», тільки чистий код, лаконічний
use TraitName і ніякого copy/pasteХоча справедливості заради варто визнати:
copy/paste все одно відбувається, просто не в коді, а на рівні інтерпретатора.🎯 Висновок
Трейти — це спосіб дотримуватися DRY і не лізти в спадкування там, де воно недоречне. Це дуже потужний інструмент якщо використовувати його правильно і там де треба.
PS:
🧠 Порада: як зробити, щоб трейт гарантовано працював в будь-якому класі без помилок?
❗️ Ніколи не звертайтесь всередині трейту до властивостей або методів класу, в який трейт підключено. Трейт не знає, куди його вставлять — і тому контекст будь-якого трейту має бути самообмеженим. Це головна умова, щоб ваш трейт працював стабільно і не викликав помилки.
Погано:
trait BadTrait {
public function generateUniqueId(): void
{
$this->id = uniqid();
}
}Добре:
trait GoodTrait {
protected string $id;
public function generateUniqueId(): void
{
$this->id = uniqid();
}
}👍8💩1
#course #php #talks #4students #tips
🧮 Який в тебе масив — асоціативний чи індексований?
В PHP масив — це універсальний інструмент, який не вимагає від тебе визначати розмір, тип елементів чи навіть структуру ключів. Це з одного боку ніби і зручно, але з іншого — є проблемою.
Більшість мов програмування виділяють масиви (indexed arrays) і словники/мапи (associative arrays), а в PHP це одна й та ж сама структура, будь-який масив може стати асоціативним або нумерованим в залежності від ключів, які ти використовуєш:
Часто виникає потреба по-різному обробляти масиви в залежності від їх типу. Але PHP не дає такої базової можливості, бо він взагалі не розрізняє індексовані та асоціативні масиви, про що прямо написано в документації.
Можна подумати, що
На перший погляд все добре, але ні.
Розширемо наш приклад, витягнемо з масиву
🙄 Що сталося з масивом? Невже він став асоціативним?
Ні. Просто
Тобто, PHP не ставить знак дорівнює між "нумерованим" та "індексованим" типами масивів.
Ще одна неприємність яка може вас очікувати: рядкові ключі — не гарантують “асоціативність”
Багато хто вважає, що якщо в масиві ключ рядковий — все, це асоціативний масив. Але якщо ключ виглядає як число, PHP конвертує його в int. Наприклад, штрихкоди товарів:
Тому на ключі типу “рядок чи число” теж покладатися не можна.
Висновок:
Чи стикаєтеся ви в роботі з такими складностями і як з них виходите?
🧮 Який в тебе масив — асоціативний чи індексований?
В PHP масив — це універсальний інструмент, який не вимагає від тебе визначати розмір, тип елементів чи навіть структуру ключів. Це з одного боку ніби і зручно, але з іншого — є проблемою.
Більшість мов програмування виділяють масиви (indexed arrays) і словники/мапи (associative arrays), а в PHP це одна й та ж сама структура, будь-який масив може стати асоціативним або нумерованим в залежності від ключів, які ти використовуєш:
$a = [1, 2, 3, 4, 5]; // індексований
$b = ['foo' => 6]; // асоціативний
$c = [
...$a,
...$b
]; // змішаний
Часто виникає потреба по-різному обробляти масиви в залежності від їх типу. Але PHP не дає такої базової можливості, бо він взагалі не розрізняє індексовані та асоціативні масиви, про що прямо написано в документації.
Можна подумати, що
array_is_list може допомогти зʼясувати хто є хтоarray_is_list($a); // true [0=>1, 1=>2, 2=>3, 3=>4, 4=>5]
array_is_list($b); // false [foo=>6]
array_is_list($c); // false [0=>1, 1=>2, 2=>3, 3=>4, 4=>5, foo=>6]
На перший погляд все добре, але ні.
Розширемо наш приклад, витягнемо з масиву
$a тільки непарні числа$a2 = array_filter($a, fn($x) => $x % 2 !== 0); // 1,3,5
array_is_list($a2); // false бо 0=>1, 2=>3, 4=>5
🙄 Що сталося з масивом? Невже він став асоціативним?
Ні. Просто
array_filter зберігає оригінальні ключі. І хоч це все ще числові ключі, але через “дірки” в індексації array_is_list повертає false. Тобто, PHP не ставить знак дорівнює між "нумерованим" та "індексованим" типами масивів.
Ще одна неприємність яка може вас очікувати: рядкові ключі — не гарантують “асоціативність”
Багато хто вважає, що якщо в масиві ключ рядковий — все, це асоціативний масив. Але якщо ключ виглядає як число, PHP конвертує його в int. Наприклад, штрихкоди товарів:
$products = [
"0123456789052" => "Товар",
"8018075001428" => "Ще товар"
];
print_r(array_keys($array));
//Array
//(
// [0] => "0123456789052"
// [1] => 8018075001428 // -- рядок став числом
//)
Тому на ключі типу “рядок чи число” теж покладатися не можна.
Висновок:
Я бачив багато коду, де масив використовують як list, а потім раптово додають рядковий ключ — і все, data integrity накрилась. Якщо твоя логіка дійсно залежить від того, який у тебе масив — перевіряй не array_is_list, а реально структуру ключів (через array_keys, is_int, is_string і т.д.). А ще краще — не лінуйся типізувати і перевіряти дані на вході, навіть якщо це PHP.
Чи стикаєтеся ви в роботі з такими складностями і як з них виходите?
👍9🗿1
#symfony #php #architecture #videoarchive
Symfony 🆚 Laravel
Знайшов і опублікував для вас запис вебінару, який я проводив в травні минулого року
В самому вебінарі не тільки порівняння вказаних фреймворків, а ще й зробив невеличкий огляд на історію розвитку фреймворків в PHP, саме порівняння стартує з 34:40
👍 Ставте лайки або дизлайки, підписуйтесь на канал і робіть все інше, що треба, щоб на YouTube ставало більше україномовного контенту
Приємного перегляду!
Альтернативні думки в коментарях до відео або цього посту вітаються
Symfony 🆚 Laravel
Знайшов і опублікував для вас запис вебінару, який я проводив в травні минулого року
В самому вебінарі не тільки порівняння вказаних фреймворків, а ще й зробив невеличкий огляд на історію розвитку фреймворків в PHP, саме порівняння стартує з 34:40
👍 Ставте лайки або дизлайки, підписуйтесь на канал і робіть все інше, що треба, щоб на YouTube ставало більше україномовного контенту
Приємного перегляду!
Альтернативні думки в коментарях до відео або цього посту вітаються
YouTube
Symfony vs Laravel / Вебінар: 22.05.2024
У цьому відео я порівнюю два найпопулярніші PHP-фреймворки — Symfony та Laravel. Розберемо, чим вони відрізняються за підходами, архітектурою та філософією розробки, які мають переваги й недоліки, та у яких проєктах кожен з них розкриває свій потенціал на…
👍13
#️⃣ #php #longread
💡 Майбутнє PHP: погляд на те, що принесе PHP 9
PHP — живіший, ніж будь-коли 😎
І хоча хтось досі вважає його “динозавром”, мова продовжує еволюціонувати. PHP 9.0 може стати тим самим моментом, коли “магія” поступиться місцем чистоті, а неочікувані трюки — передбачуваності.
🕒 Офіційної дати коли чекати PHP 9 ще немає, але RFC-дискусії вже киплять.
Після 8.5 (і можливо 8.6) ми отримаємо більш суворий, логічний і, що важливо, стабільний PHP.
Тож якщо ти ще не стежиш за RFC — то я поділюся з тобою цією інформацією 👀
1️⃣ Оператори ++ / -- стануть чеснішими
Тепер ніяких дивних перетворень рядків у цифри.
🧩 Менше “магії”
2️⃣ unserialize() кидатиме винятки
🧠 Виключення замість warning
3️⃣ Менше перевизначень типив
🙅♂️ Тепер буде помилка, а не постріл в коліно
4️⃣ Інтерполяція рядків — без зайвої магії
✨ Приведення до єдиного стандарту
5️⃣ Попередження == fatal error
Невизначені змінні, властивості чи звернення до null більше не проходитимуть "якось"
🧱 PHP буде вимогливішим до якості коду — і це добре.
6️⃣ Прибирання старих “речей”
Старі конструктори, застарілі функції, нестандартна логіка — все це піде в архів 📦
Менше сміття, менше двозначностей.
🚀 Підсумок
Якщо твій код вже чистий, суворо типізований і без магії — тобі нема чого боятися 💪
💡 Майбутнє PHP: погляд на те, що принесе PHP 9
PHP — живіший, ніж будь-коли 😎
І хоча хтось досі вважає його “динозавром”, мова продовжує еволюціонувати. PHP 9.0 може стати тим самим моментом, коли “магія” поступиться місцем чистоті, а неочікувані трюки — передбачуваності.
🕒 Офіційної дати коли чекати PHP 9 ще немає, але RFC-дискусії вже киплять.
Після 8.5 (і можливо 8.6) ми отримаємо більш суворий, логічний і, що важливо, стабільний PHP.
Тож якщо ти ще не стежиш за RFC — то я поділюся з тобою цією інформацією 👀
1️⃣ Оператори ++ / -- стануть чеснішими
Тепер ніяких дивних перетворень рядків у цифри.
$a = 'a9';
$a++;
// PHP < 9.0 -> 'b0'
// PHP 9.0 -> TypeError
🧩 Менше “магії”
2️⃣ unserialize() кидатиме винятки
try {
$obj = unserialize($data);
} catch (UnserializationFailedException $e) {
// handle
}🧠 Виключення замість warning
3️⃣ Менше перевизначень типив
$arr = false;
$arr[] = 2;
// PHP < 9.0 -> [2]
// PHP 9.0 -> Error
🙅♂️ Тепер буде помилка, а не постріл в коліно
4️⃣ Інтерполяція рядків — без зайвої магії
$name = "Alex";
echo "Hello $name"; // ✅
echo "Hello {$name}"; // ✅
echo "Hello ${name}"; // ❌ Deprecation
✨ Приведення до єдиного стандарту
5️⃣ Попередження == fatal error
Невизначені змінні, властивості чи звернення до null більше не проходитимуть "якось"
echo $undefinedVar;
// PHP < 9.0 -> Попередження
// PHP 9.0 -> Фатальна помилка
🧱 PHP буде вимогливішим до якості коду — і це добре.
6️⃣ Прибирання старих “речей”
Старі конструктори, застарілі функції, нестандартна логіка — все це піде в архів 📦
Менше сміття, менше двозначностей.
🚀 Підсумок
PHP 9.0 — має кардинально змінити підхід до написання коду та його культури.
Менше вседозволеності, більше контролю.
Якщо твій код вже чистий, суворо типізований і без магії — тобі нема чого боятися 💪
🔥11👍6
#php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 1/10
10 потужних інструментів, які тобі слід використовувати 🧠
Кожен реліз PHP приносить нові можливості, що роблять код коротшим, розумнішим і приємнішим у підтримці.
Але, як показує досвід численних співбесід і консультацій, більшість із них проходять повз увагу навіть досвідчених розробників.
Ця серія — для тих, хто, як і я, прагне по-справжньому розкрити потенціал PHP і кайфувати від розробки 💥
Ми розберемо 10 фіч, які:
🔹 доступні з PHP 5.5, але досі поза увагою
🔹 реально спрощують код
🔹 показують, наскільки PHP універсальний
——————
Перша стаття серії
⚙️ Property Promotion
Менше коду — легше читати 💡
📦 Додано у версії: PHP 8.0
💡 Що дає: можливість оголошувати властивості класу прямо в конструкторі — без дублювання й шаблонного коду.
🚀 Чому це крутіше за старий підхід
— не потрібно окремо описувати властивості та привласнювати їх значення у конструкторі;
— менше шуму — одразу видно структуру класу;
— ідеально підходить для DTO, запитів, VO, команд, конфігів тощо.
🧠 Фактично це "data class" по-PHPшному — коротко, без додаткових бібліотек чи автогенерації коду.
🧱 Реальний приклад застосування
📌 У коді це зменшує бойлерплейт майже втричі, а клас стає самоочевидним.
🧩 Де це реально корисно
— DTO у запитах/відповідях API;
— командні об’єкти в CQRS;
— значення, які описують одну сутність без поведінки (Value Object);
— Symfony-форми, коли треба швидко пробросити дані.
🧭 Висновок
———
Анонімні класи ➡️
🚀 Чи знаєш ти, що PHP так вміє? 1/10
10 потужних інструментів, які тобі слід використовувати 🧠
Кожен реліз PHP приносить нові можливості, що роблять код коротшим, розумнішим і приємнішим у підтримці.
Але, як показує досвід численних співбесід і консультацій, більшість із них проходять повз увагу навіть досвідчених розробників.
Ця серія — для тих, хто, як і я, прагне по-справжньому розкрити потенціал PHP і кайфувати від розробки 💥
Ми розберемо 10 фіч, які:
🔹 доступні з PHP 5.5, але досі поза увагою
🔹 реально спрощують код
🔹 показують, наскільки PHP універсальний
——————
Перша стаття серії
⚙️ Property Promotion
Менше коду — легше читати 💡
📦 Додано у версії: PHP 8.0
💡 Що дає: можливість оголошувати властивості класу прямо в конструкторі — без дублювання й шаблонного коду.
🚀 Чому це крутіше за старий підхід
— не потрібно окремо описувати властивості та привласнювати їх значення у конструкторі;
— менше шуму — одразу видно структуру класу;
— ідеально підходить для DTO, запитів, VO, команд, конфігів тощо.
🧠 Фактично це "data class" по-PHPшному — коротко, без додаткових бібліотек чи автогенерації коду.
🧱 Реальний приклад застосування
// ❌ Раніше
readonly class Product {
public string $sku;
public string $name;
public float $price;
public function __construct(string $sku, string $name, float $price) {
$this->sku = $sku;
$this->name = $name;
$this->price = $price;
}
}
// ✅ Тепер
readonly class Product {
public function __construct(
public string $sku,
public string $name,
public float $price,
) {}
}
📌 У коді це зменшує бойлерплейт майже втричі, а клас стає самоочевидним.
🧩 Де це реально корисно
— DTO у запитах/відповідях API;
— командні об’єкти в CQRS;
— значення, які описують одну сутність без поведінки (Value Object);
— Symfony-форми, коли треба швидко пробросити дані.
class CreateUserCommand {
public function __construct(
public string $email,
public string $password,
public bool $isAdmin = false,
) {}
}🧭 Висновок
✨ Property Promotion — не просто синтаксичний цукор, це офіційний перехід до декларативного стилю.
Код виглядає лаконічніше, без зайвих рядків.
———
Анонімні класи ➡️
👍9❤1🔥1
#️⃣ #php #course #series
🚀 Чи знаєш ти, що PHP так вміє? 2/10
🧩 Анонімні класи
Давня фіча, яку безліч розробників досі ігнорують 🤷♂️
📦 Додано у версії: PHP 7.0
💡 Що дає: можливість створювати клас “на льоту” — без імені, без окремого файлу, просто у місці, де він реально потрібен.
🧠 Чому про це варто згадати
Попри те, що анонімні класи з’явилися ще у PHP 7, спілкування з розробниками показує приблизно таку статистику:
🔹9 з 10 не бачать для них “практичного сенсу”,
🔹7 з 10 — ніколи не пробували створити
А дарма — це інструмент, який ідеально підходить для тимчасових об’єктів, адаптерів, обгорток і стратегій.
⚙️ Коли анонімні класи реально зручні
— коли потрібен mock обʼєкт для тестів;
— коли треба підмінити поведінку об’єкта лише тут і зараз;
— коли не хочеться створювати окремий клас заради дрібної логіки;
— коли потрібно “локально” адаптувати чи розширити поведінку;
— коли потрібен короткий об’єкт із власним станом або кількома методами.
🧱 Реальний приклад застосування
Не буду наводити приклад створення mockів для тестів, цих прикладів повно в інтернеті, натомість поділюся більш практичним застосуванням анонімних класів.
🔹 Тимчасовий адаптер
✅ Пара рядків і є готовий адаптер без створення файлу.
🔹 Локальна стратегія або callback-об’єкт
✅ Callable з методом і власним станом.
Результат отримаємо для сімох елементів, а процес запуститься лише тричі
🔹 Тимчасовий listener для події
✅ Одноразовий слухач — і не треба роздувати кількість файлів в проєкті
🔹 DTO “на льоту”
✅ Коли є зайвим створювати окрему структуру для разового результату.
🧭 Висновок
🔥 Якщо ти теж ще не пробував
———
⬅️ Property Promotion | Стрілкові функції ➡️
🚀 Чи знаєш ти, що PHP так вміє? 2/10
🧩 Анонімні класи
Давня фіча, яку безліч розробників досі ігнорують 🤷♂️
📦 Додано у версії: PHP 7.0
💡 Що дає: можливість створювати клас “на льоту” — без імені, без окремого файлу, просто у місці, де він реально потрібен.
🧠 Чому про це варто згадати
Попри те, що анонімні класи з’явилися ще у PHP 7, спілкування з розробниками показує приблизно таку статистику:
🔹9 з 10 не бачать для них “практичного сенсу”,
🔹7 з 10 — ніколи не пробували створити
new class {} навіть у петпроєктах або чернетках.А дарма — це інструмент, який ідеально підходить для тимчасових об’єктів, адаптерів, обгорток і стратегій.
⚙️ Коли анонімні класи реально зручні
— коли потрібен mock обʼєкт для тестів;
— коли треба підмінити поведінку об’єкта лише тут і зараз;
— коли не хочеться створювати окремий клас заради дрібної логіки;
— коли потрібно “локально” адаптувати чи розширити поведінку;
— коли потрібен короткий об’єкт із власним станом або кількома методами.
🧱 Реальний приклад застосування
Не буду наводити приклад створення mockів для тестів, цих прикладів повно в інтернеті, натомість поділюся більш практичним застосуванням анонімних класів.
🔹 Тимчасовий адаптер
$adapter = new class($apiClient) implements PaymentGateway
{
public function __construct(private ApiClient $api) {}
public function pay(float $amount): bool {
return $this->api->request('/pay', ['sum' => $amount]);
}
};
$adapter->pay(9.99);
✅ Пара рядків і є готовий адаптер без створення файлу.
🔹 Локальна стратегія або callback-об’єкт
$transformer = new class
{
public array $alreadyTransform = [];
public function transform(int $v): int
{
return $this->alreadyTransform[$v] ??= $v*10;
}
};
$result = array_map(
$transformer->transform(...),
[1, 2, 3, 2, 1, 2, 3]
);
var_dump($result); //[10, 20, 30, 20, 10, 20, 30]
✅ Callable з методом і власним станом.
Результат отримаємо для сімох елементів, а процес запуститься лише тричі
🔹 Тимчасовий listener для події
$dispatcher->addListener('user.registered', new class {
public function __invoke(User $user): void {
// логування, повідомлення, email — все що завгодно
}
});✅ Одноразовий слухач — і не треба роздувати кількість файлів в проєкті
🔹 DTO “на льоту”
return new class($user, $stats) {
public function __construct(
public User $user,
public array $stats
) {}
public function total(): int {
return array_sum($this->stats);
}
};✅ Коли є зайвим створювати окрему структуру для разового результату.
🧭 Висновок
Анонімні класи — це старий, але дуже недооцінений інструмент.
Вони економлять час, зменшують кількість файлів і дозволяють тримати тимчасову логіку саме там, де вона потрібна.
🔥 Якщо ти теж ще не пробував
new class {}, зроби це сьогодні. Можливо, відкриєш для себе новий улюблений трюк PHP———
⬅️ Property Promotion | Стрілкові функції ➡️
👍4❤2
#️⃣ #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
#️⃣ #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
#️⃣ #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 #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
#php #composer #security
🚨 Оновіть Composer до версії 2.9.6 або 2.2.27 (LTS)
В Composer виправили вразливості
Через Perforce driver можна було підсунути значення, які попадали в shell-команди без екранування, як результат — це була command injection в вашій консолі.
Нічого критично нового, але ще один сигнал, що безпека supply chain — це не теорія, а реальність.
🧠 Цей сухий факт, це ще одне нагадування про очевидну, але часто ігноровану річ:
І не тільки через scripts в
А і на рівні самого composer
💥 Найнеприємніше
Навіть якщо ти навіть не використовуєш Perforce, dependency може змусити composer виконати команду.
📌 Без оновлення composer ти в зоні ризику якщо:
— ставиш пакети з source
— працюєш з dev-версіями
— підключаєш кастомні репозиторії
— просто запускаєш composer на чужому коді
✅ Що робити?
— оновити composer (там вже пофіксили)
— по можливості використовувати dist замість source
— менше довіряти всьому підряд
🧭 Моя позиція
Composer давно перестав бути просто менеджером залежностей, сьогодні це повноцінний execution layer і кожен
🚨 Оновіть Composer до версії 2.9.6 або 2.2.27 (LTS)
В Composer виправили вразливості
CVE-2026-40176, CVE-2026-40261Через Perforce driver можна було підсунути значення, які попадали в shell-команди без екранування, як результат — це була command injection в вашій консолі.
Нічого критично нового, але ще один сигнал, що безпека supply chain — це не теорія, а реальність.
🧠 Цей сухий факт, це ще одне нагадування про очевидну, але часто ігноровану річ:
composer install === виконання чужого коду на своєму компіІ не тільки через scripts в
composer.jsonА і на рівні самого composer
💥 Найнеприємніше
Навіть якщо ти навіть не використовуєш Perforce, dependency може змусити composer виконати команду.
📌 Без оновлення composer ти в зоні ризику якщо:
— ставиш пакети з source
— працюєш з dev-версіями
— підключаєш кастомні репозиторії
— просто запускаєш composer на чужому коді
✅ Що робити?
— оновити composer (там вже пофіксили)
— по можливості використовувати dist замість source
— менше довіряти всьому підряд
🧭 Моя позиція
Composer давно перестав бути просто менеджером залежностей, сьогодні це повноцінний execution layer і кожен
composer install — це маленький "bash" з інтернету, перед підключенням кастомних залежностей потрібно оцінювати що саме воно буде тягнути за собою.🔥8🤯1