A variadic parameter lets a function accept a variable number of arguments. PHP collects them into an array, so function total(int ...$values) can handle two numbers, five numbers or no numbers. Argument unpacking does the reverse: it takes values from an array or traversable input and supplies them as arguments.
Named arguments, introduced in PHP 8.0, let callers use parameter names rather than only positions. They can make a call with optional settings clearer, but they also make parameter names part of the public contract. This guide connects all three features and explains the ordering rules that matter when refactoring a function.
Variadic parameters collect the remaining arguments
Place ... before the parameter variable to collect additional arguments. The variadic parameter must be last because it consumes the remaining supplied arguments. Fixed parameters can precede it, such as a separator followed by any number of labels. Inside the function, the collected values are an array.
A type declaration applies to each collected argument, not to the resulting array as a whole. With int ...$values, every supplied variadic item must satisfy PHP's integer parameter rules. The function still needs domain checks if integers must be nonnegative or within a range. Accepting any number of integers does not mean unlimited memory or computation is sensible.
Decide what zero arguments means. A sum can naturally return zero. A function selecting the largest value may need to reject an empty set. State that rule explicitly rather than letting an underlying built-in fail unexpectedly. A variable-length interface should still have a precise behavioral contract.
Unpacking is not the same as passing an array
total($batch) passes one array argument, which does not fit an integer variadic parameter. total(...$batch) supplies the elements as arguments. Use unpacking only when the array's shape matches the intended call. A record with unrelated fields should not be unpacked into a function merely because the names seem similar.
In PHP 8, string keys in an unpacked argument array are interpreted as named arguments. Integer keys supply positional arguments. That means an associative array can change which parameters receive values. Do not forward unvalidated request fields through unpacking: unknown names, collisions or ordering can produce errors or expose options the endpoint should not accept.
Arrays used as call configuration should have an explicit allowlist and value validation. If only two settings are approved, extract those settings and call the function deliberately. Unpacking is concise, but it should not blur the boundary between external data and an internal function signature.
Named arguments and skipped defaults
Write parameterName: value at the call site to select a parameter by name. Named arguments can be supplied in a different order, and you can omit earlier optional parameters while specifying a later one. This is helpful for APIs with several optional settings whose positional order is hard to remember.
Positional arguments must come before named arguments. You cannot supply a parameter twice, once positionally and again by name. Unknown parameter names normally fail, although a variadic parameter can collect unmatched named arguments according to its contract. Spell names exactly and avoid treating every unknown name as harmless configuration.
Renaming a public parameter can break named callers even when positional callers continue to work. Library maintainers should therefore consider parameter names part of their compatibility policy. Interfaces and overriding methods also deserve consistent parameter naming if callers use named arguments through the abstraction.
PHP Variable-Length and Named Arguments Examples
Each example shows the code, the output it produces and what each part does.
Sum a variable number of values
The first call collects three values. The second collects an empty array. The third unpacks an ordinary numeric list into two separate arguments. The example uses small values; production code handling large integers should consider overflow rather than assuming every sum remains an int.
<?php
declare(strict_types=1);
function total(int ...$values): int {
return array_sum($values);
}
echo total(2, 3, 4) . PHP_EOL;
echo total() . PHP_EOL;
$batch = [5, 6];
echo total(...$batch) . PHP_EOL;9
0
11Skip an optional setting by name
The first call skips prefix while specifying suffix. The second begins with a positional name and then supplies a named suffix. Both obey the positional-before-named rule. A reader can understand the optional setting without remembering its third position.
<?php
function label(string $name, string $prefix = '', string $suffix = ''): string {
return $prefix . $name . $suffix;
}
echo label(name: 'Pen', suffix: '!') . PHP_EOL;
echo label('Book', suffix: '?') . PHP_EOL;Pen!
Book?Common PHP Variable-Length and Named Arguments Mistakes
Confusing forwarding with a stable API
Automatically forwarding a map of options into another library can couple your endpoint to that library's parameter names. A library upgrade or parameter rename may change behavior. Write a small adapter that maps your public fields to the library's explicit call when the endpoint needs a stable contract.
Avoid unnecessary reliance on func_get_args() for new variadic functions. The declared variadic parameter gives the collected values an understandable name and supports types directly. The PHP arguments reference documents variadics, unpacking, named arguments and version-specific combinations. In particular, review compatibility before mixing unpacked and named arguments across different PHP 8 minor versions.
PHP Variable-Length and Named Arguments in Real Projects
Practical task: join a variable label list
Create a helper with a fixed separator parameter followed by any number of string labels. Then call it once with individual arguments and once by unpacking a validated list. Empty input should produce an empty string. This contract matches a simple display transformation and avoids unnecessary global state.
<?php
declare(strict_types=1);
function joinLabels(string $separator, string ...$labels): string {
return implode($separator, $labels);
}
echo joinLabels(' / ', 'Pen', 'Book') . PHP_EOL;
$labels = ['Blue', 'Green', 'Red'];
echo joinLabels(' + ', ...$labels) . PHP_EOL;
echo '[' . joinLabels(',') . ']' . PHP_EOL;Pen / Book
Blue + Green + Red
[]The fixed argument is followed by variadic values. Try supplying an integer under strict_types and observe the type error in a separate experiment. If an external JSON array supplies labels, validate every element as a bounded string first. A type error is not a polished API validation response and should not become your only input policy.
PHP Variable-Length and Named Arguments FAQ
Can a variadic parameter come first?
It must be the last declared parameter. Put fixed requirements before it.
Does ... always mean the same operation?
No. In a parameter declaration it collects arguments. At a call site it unpacks them. Other array contexts have their own spreading behavior.
Can named arguments skip a default?
Yes. You can name a later optional parameter while earlier optional parameters keep their defaults.
Why did an associative array change my call?
PHP 8 treats string keys in unpacked arguments as parameter names. Validate the map and avoid uncontrolled forwarding.
Can I rename a parameter safely?
Positional callers may survive, but named callers can break. Treat publicly used parameter names as compatibility-sensitive.
PHP Variable-Length and Named Arguments Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
How do you supply the elements of $numbers as separate arguments to total()?
PHP Variable-Length and Named Arguments Quiz
2 questions to check what you learned.
What does int ...$values create inside the function?
- One concatenated string
- An array of collected arguments
- A global constant
Which argument ordering is allowed?
- Named arguments followed by ordinary positional arguments
- The same parameter supplied twice
- Positional arguments followed by named arguments