doc-en icon indicating copy to clipboard operation
doc-en copied to clipboard

Using named parameters with a variadic parameter

Open kbond opened this issue 3 years ago • 2 comments

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

kbond avatar Nov 25 '22 15:11 kbond

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 array
  • foo(flags: ['bar', 'baz']) - not valid because each of the flags is supposed to be a string and you're passing an array
  • foo(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...

damianwadley avatar Nov 25 '22 23:11 damianwadley

Makes sense, thanks for the great explanation @damianwadley!

kbond avatar Nov 26 '22 00:11 kbond