Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Що робити з методом, який приймає вісім параметрів?

Довгий список параметрів - code smell: виклик важко читати, легко переплутати порядок аргументів однакового типу, а кожна зміна сигнатури зачіпає всі місця виклику.

$this->createInvoice($customerId, $amount, 'UAH', $dueDate, true, false, null, 'uk');
// що означають true, false і null?

Варіанти лікування:

1. Об'єкт параметрів (Introduce Parameter Object) - параметри, що завжди йдуть разом, об'єднуються в клас:

final readonly class InvoiceData
{
    public function __construct(
        public int $customerId,
        public Money $amount,
        public DateTimeImmutable $dueDate,
        public bool $sendByEmail = true,
        public bool $isDraft = false,
        public ?string $note = null,
        public string $locale = 'uk',
    ) {}
}

$this->createInvoice(new InvoiceData(
    customerId: $customer->id,
    amount: Money::uah(125050),
    dueDate: now()->addDays(14)->toImmutable(),
));

Іменовані аргументи PHP 8 роблять створення читабельним, значення за замовчуванням прибирають шум, а readonly гарантує незмінність. Часто в такий об'єкт перетікає й логіка (валідація, обчислення), - він стає об'єктом-значенням, а не просто контейнером.

2. Іменовані аргументи без нового класу - для рідкісних викликів з кількома необов'язковими параметрами:

$this->createInvoice($customerId, $amount, dueDate: $date, isDraft: true);

3. Передавати весь об'єкт замість його частин (Preserve Whole Object): calculateShipping($order) замість calculateShipping($order->weight, $order->country, $order->city, $order->express).

4. Прибрати булеві прапорці (Remove Flag Argument): createInvoice(..., isDraft: true) часто означає два різні методи - createDraftInvoice() і issueInvoice().

5. Перенести параметри в конструктор: залежності (сервіси, конфігурація), що передаються в кожен виклик, - у конструктор класу через впровадження залежностей.

Ознака, що проблема глибша: метод приймає багато параметрів, бо робить забагато. Тоді спершу розділити метод (Extract Method/Class), а вже потім дивитися на параметри.

У Laravel-проєктах такі об'єкти часто будують з Form Request ($request->toDto()) чи використовують spatie/laravel-data, що поєднує DTO з валідацією й перетворенням з/у масив.

Докладніше в документації: Каталог рефакторингів: Introduce Parameter Object

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання