PHP 8.0 lets you pass arguments by parameter name, in any order, skipping optional ones; positional arguments come first. A variadic parameter, int ...$n, collects the remaining arguments into an array, replacing func_get_args(). At a call site ... spreads an array into arguments, and since 8.1 its string keys count as names.
<?php
declare(strict_types=1);
function user(string $name, int $age = 18, string $country = 'US'): string
{
return "$name ($age, $country)";
}
function total(int ...$n): int { return array_sum($n); }
echo user(name: 'Ann', country: 'UK', age: 30), ' | ', user('Bob', country: 'CA'), "\n";
echo user(...['name' => 'Cleo', 'age' => 41]), ' | ', total(1, 2, ...[3, 4]), "\n";
echo htmlspecialchars('& <b>', double_encode: false), "\n";Output
Ann (30, UK) | Bob (18, CA) Cleo (41, US) | 10 & <b>
The last line is the everyday win: reaching the fourth parameter of a built-in without restating two defaults. The cost is that parameter names become public API: rename $country and callers that named it fail with Unknown named parameter $country.