php / doc-en

English PHP documentation
488 stars 724 forks source link

array_intersect doesn't support named arguments #3233

Open kkmuffme opened 6 months ago

kkmuffme commented 6 months ago

From manual page: https://php.net/function.array-intersect


array_intersect(arrays: $a, array: $b);
array_intersect(hello: $a, world: $c, array: $b);

When named arguments are supported this works normally, see

function foo($array, ...$arrays) {}
foo(arrays: $a, array: $b);
foo(hello: $a, world: $c, array: $b);

This isn't documented anywhere though. This also affects https://www.php.net/manual/en/function.array-intersect-key.php and possibly a variety of other functions.

EDIT: this seems to be wrong for all functions that are documented with This function can now be called with only one parameter. Formerly, at least two parameters have been required. e.g. arary_diff,... too

EDIT2: looks like other functions that are not annotated like that, e.g. sprintf have the same issue.

damianwadley commented 6 months ago

The problem I see is that the function arguments docs talk about ... argument lists and about named parameters but does not talk about what happens when you mix the two of them together.

What happens is that ... will gather together all the unknown named arguments used. Goes like this:

function foo($array, ...$arrays) { }

foo(hello: $a, world: $b, array: $c);
// $array = $c and $arrays = ["hello" => $a, "world" => $b]

Theoretically, if you called array_intersect in a similar manner, you would get a similar result:

// function array_intersect($array, ...$arrays) { }

array_intersect(hello: $a, world: $b, array: $c);
// $array = $c and $arrays = ["hello" => $a, "world" => $b]

But as far as I can see, that behavior simply isn't allowed in the internal functions - as in, when a function processes its arguments, if there were any named arguments passed that didn't correspond to actual named parameters then it throws an ArgumentCountError. In userland, you get the same result with:

function foo($array, ...$arrays) {
    // $arrays will always have integer keys for positional arguments and string keys for named arguments
    if (!array_is_list($arrays)) {
        throw new ArgumentCountError(__FUNCTION__ . "() does not accept unknown named parameters");
    }

The same thing happens with other varargs functions, like min/max and s/printf.

It would be a lot to call this behavior out explicitly for every single function that it applies to, so instead, I think the function arguments page really ought to document this sort of behavior: how it works for userland function, and how it doesn't work (or rather, isn't allowed) for built-in functions.

So:

When named arguments are supported this works normally,

It works, but in a different way than it seems you think it works, and the built-in functions - nearly all of them because they use some shared code to process their arguments - specifically don't want to be called that way.

this seems to be wrong for all functions that are documented with This function can now be called with only one parameter. Formerly, at least two parameters have been required. e.g. arary_diff,... too

In that those functions also use variable-length argument lists, yes. But the fact that they support only one argument ($array has a value and $arrays is an empty) is a separate matter.

Girgias commented 6 months ago

The whole function/function argument section of the manual needs to be rewriten and I have had this on ;y list for a year at least :/

kkmuffme commented 6 months ago

@Girgias thanks, I couldn't find anything with the search, therefore I opened the issue. Good that it's on the roadmap already.

@damianwadley what exactly are you trying to say with your comment that isn't already covered by the original issue?

It works, but in a different way than it seems you think it works

How? It works exactly as I think it would work with user land functions?