Проблема: однаковий switch за типом повторюється в багатьох місцях. Новий тип - зміни в кожному з них, і одне точно забудуть.
function fee(Payment $p): int
{
return match ($p->method) {
'card' => (int) ($p->amount * 0.025),
'bank_transfer' => 500,
'cash' => 0,
};
}
// і ще схожі match для label(), isRefundable(), icon()...
Варіант 1 - enum з методами (PHP 8.1+). Добре, коли поведінка невелика й залежить лише від типу:
enum PaymentMethod: string
{
case Card = 'card';
case BankTransfer = 'bank_transfer';
case Cash = 'cash';
public function fee(int $amount): int
{
return match ($this) {
self::Card => (int) ($amount * 0.025),
self::BankTransfer => 500,
self::Cash => 0,
};
}
}
Знання про тип зібране в одному місці, а match без default змусить обробити новий випадок - інакше UnhandledMatchError, а статичний аналізатор попередить ще раніше.
Варіант 2 - поліморфізм (класи за спільним інтерфейсом). Коли в кожного типу своя складна логіка чи залежності:
interface PaymentProcessor
{
public function fee(int $amount): int;
public function refund(Payment $payment): void;
}
final class CardProcessor implements PaymentProcessor { /* ... */ }
Вибір реалізації - один раз, у фабриці чи контейнері. Далі код викликає методи без розгалужень.
Коли switch нормальний: він трапляється в одному місці (наприклад, у фабриці, що створює потрібний об'єкт), варіантів мало і їхній список стабільний. Поліморфізм заради одного if - зайве ускладнення.
Докладніше в документації: Replace Conditional with Polymorphism