Named arguments и spread
Named arguments
PHP 8.0+ — передача аргументов по имени:
function createUser(string $name, int $age, bool $admin = false): User
{
// ...
}
// Позиционно
createUser('Иван', 25, true);
// По имени
createUser(name: 'Иван', age: 25, admin: true);
Зачем
Читаемость:
// Что это за true? Непонятно
createUser('Иван', 25, true);
// Понятно
createUser(name: 'Иван', age: 25, admin: true);
Пропуск необязательных:
createUser(name: 'Иван', age: 25); // admin по умолчанию
Порядок не важен:
createUser(age: 25, name: 'Иван');
Смешивание
Можно смешивать позиционные и именованные:
createUser('Иван', age: 25, admin: true);
Правило: позиционные до именованных.
Ошибка:
createUser(name: 'Иван', 25, admin: true); // нельзя
Работа с внутренними функциями
Встроенные функции тоже поддерживают:
htmlspecialchars($text, double_encode: false);
array_slice($arr, offset: 1, length: 2);
str_replace(search: 'a', replace: 'b', subject: $text);
Полезно для функций с длинным списком параметров.
С опциональными
function formatDate(
string $date,
string $format = 'Y-m-d',
?string $timezone = null,
): string {
// ...
}
formatDate('2026-10-15', timezone: 'Europe/Moscow');
// format остаётся по умолчанию
С variadic
function sum(int ...$numbers): int
{
return array_sum($numbers);
}
// Named args не применимы к variadic
Нельзя sum(numbers: 1, 2, 3).
Spread
Распаковка массива:
$args = [1, 2, 3];
sum(...$args);
PHP 8.1+ — именованный spread:
$args = ['a' => 1, 'b' => 2];
sum(...$args);
// эквивалентно sum(a: 1, b: 2)
Смешанный:
$args = [10, 'b' => 20];
sum(...$args); // sum(10, b: 20)
Практический пример
Конфиг с defaults:
function connect(
string $host,
int $port = 5432,
string $database = 'postgres',
string $user = 'postgres',
string $password = '',
array $options = [],
): PDO {
// ...
}
// Хочу только host и password
connect(
host: 'localhost',
password: 'secret',
);
Без named args:
connect('localhost', 5432, 'postgres', 'postgres', 'secret');
// или через массив
С массивами
array_merge:
$base = ['a' => 1, 'b' => 2];
$override = ['b' => 3, 'c' => 4];
$merged = [...$base, ...$override];
// ['a' => 1, 'b' => 3, 'c' => 4]
С числовыми ключами:
$a = [1, 2];
$b = [3, 4];
$c = [...$a, ...$b]; // [1, 2, 3, 4]
PHP 8.1+ — со строковыми ключами тоже:
$a = ['x' => 1];
$b = ['y' => 2];
$c = [...$a, ...$b]; // ['x' => 1, 'y' => 2]
До 8.1 — строковые ключи не поддерживались.
Spread в аргументах
function log(string $level, string ...$messages): void { }
$messages = ['msg1', 'msg2', 'msg3'];
log('ERROR', ...$messages);
Named args и рефакторинг
⚠️ Осторожно:
function createUser(string $name, int $age): void { }
// В коде
createUser(name: 'Иван', age: 25);
// Переименовали параметр
function createUser(string $fullName, int $age): void { }
// Код сломался: Unknown named parameter $name
Правило: публичные API — стабильные имена параметров.
PHPDoc @no-named-arguments — пометить функцию, где named args не гарантируются:
/**
* @no-named-arguments
*/
function f($a, $b) { }
Named args в классах
В конструктор:
class User
{
public function __construct(
public string $name,
public int $age,
public bool $admin = false,
) {}
}
$user = new User(
name: 'Иван',
age: 25,
admin: true,
);
Очень удобно для DTO и value objects.
Позиция по умолчанию
Порядок не важен, если все переданы по имени:
$user = new User(
admin: true,
age: 25,
name: 'Иван',
);
Динамические ключи
Можно через переменную:
$argName = 'age';
createUser(name: 'Иван', ...[$argName => 25]);
Используется редко.
Отладка
Ошибка при опечатке:
createUser(nam: 'Иван', age: 25);
// Error: Unknown named parameter $nam
Хорошо — ловится сразу.
Сравнение с массивами-опциями
Старый стиль (массив):
function createUser(array $options): void
{
$name = $options['name'] ?? '';
$age = $options['age'] ?? 0;
// ...
}
createUser(['name' => 'Иван', 'age' => 25]);
Минусы:
- Нет типизации внутри.
- Опечатки в ключах не ловятся.
- Нужны проверки.
Named args:
- Типы проверяются.
- Опечатки ловятся.
- IDE подсказывает.
Вывод: для 3+ параметров — named args.
Практика
<?php
declare(strict_types=1);
final class Email
{
public function __construct(
public readonly string $to,
public readonly string $subject,
public readonly string $body,
public readonly array $cc = [],
public readonly array $bcc = [],
public readonly bool $html = false,
) {}
}
$email = new Email(
to: 'user@example.com',
subject: 'Привет',
body: '<h1>Hello</h1>',
html: true,
cc: ['manager@example.com'],
);
function send(Email ...$emails): void
{
foreach ($emails as $email) {
echo "Отправка на {$email->to}\n";
}
}
$emails = [
new Email(to: 'a@ex.com', subject: 'A', body: 'A body'),
new Email(to: 'b@ex.com', subject: 'B', body: 'B body'),
];
send(...$emails);
Итог
- Named args — по имени, читаемо, порядок не важен.
- Позиционные до именованных.
- Опциональные можно пропускать.
- Spread —
...$arrв вызовах и массивах. - PHP 8.1+ — именованный spread.
- Переименование параметров ломает код — будь аккуратен.
- Для 3+ параметров — почти всегда лучше.
Дальше — nullsafe operator.