doc-en
doc-en copied to clipboard
Using named parameters with a variadic parameter
Description
Consider the following code:
function foo(int $a = 0, int $b = 0, string ...$flags) {}
It is not possible to pass more than one value to $flags when using named parameters:
foo(flags: 'bar'); // valid
foo(flags: 'bar', 'baz'); // Fatal error: Cannot use positional argument after named argument
foo(flags: ['bar', 'baz']); // Fatal error: Uncaught TypeError: foo(): Argument php/php-src#3 must be of type string, array given
foo(flags: ...['bar', 'baz']); // Parse error: syntax error, unexpected token "..."
Additionally, foo(flags: 'bar'); results in the $flags being:
[
'flags': 'bar',
]
Not sure if this is expected but I expected it to be ['bar'].
PHP Version
8.0+
Operating System
No response
That is the expected behavior: basically, naming and unpacking arguments combine to form a sort of "arbitrary arguments" ability, where $flags will contain all the extra arguments. That supports a different use case than the one you're intending.
Regarding the syntax, it really is what the messages say:
foo(flags: 'bar', 'baz')- not valid because "baz" looks like a positional argument, and PHP can't "look into" the called function's parameters to see that flags is an arrayfoo(flags: ['bar', 'baz'])- not valid because each of theflagsis supposed to be a string and you're passing an arrayfoo(flags: ...['bar', 'baz'])- this could potentially have been valid, but the "arbitrary arguments" design just doesn't work this way
The correct method, by which I mean the syntax that is intended to work and not necessarily what you wanted to do, is to make your $flags array be key/value associations of flags. Provided that none of those flags are named "a" or "b", you can unpack that without needing to specify the flags: name because PHP will infer that automatically.
<?php
function foo(int $a = 0, int $b = 0, mixed ...$flags) { var_dump($flags); }
foo(...["bar" => true, "baz" => false]);
https://3v4l.org/AQ42R
I don't see any of this documented in the official docs nearly as well as it is in the RFC, so...
Makes sense, thanks for the great explanation @damianwadley!