Skip to content

Commit

Permalink
Allow named args after unpack
Browse files Browse the repository at this point in the history
Currently, argument unpacking and named arguments cannot be mixed
at all. This relaxes the restriction to allow
foo(...$args, named: $arg). The variant foo(named: $arg, ...$args)
is still forbidden, because we can't ensure that positional
parameters come before named parameters in that case (without more
intrusive changes). Effectively this just enforces a required style,
as the order of unpack and named args doesn't matter for the cases
where both could be well-defined.

ML discussion: https://externals.io/message/114589

Closes GH-7009.
  • Loading branch information
nikic committed Jun 14, 2021
1 parent 71fb835 commit 1c08f8a
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 13 deletions.
2 changes: 2 additions & 0 deletions UPGRADING
Expand Up @@ -185,6 +185,8 @@ PHP 8.1 UPGRADE NOTES
. File uploads now provide an additional full_path key, which contains the
full path (rather than just the basename) of the uploaded file. This is
intended for use in conjunction with "upload webkitdirectory".
. It is now allowed to specify named arguments after an argument unpack, e.g.
foo(...$args, named: $arg).

- Curl:
. Added CURLOPT_DOH_URL option.
Expand Down
56 changes: 52 additions & 4 deletions Zend/tests/named_params/unpack_and_named_1.phpt
@@ -1,10 +1,58 @@
--TEST--
Mixing unpacking and named params (1)
Named args after unpacking (supported)
--FILE--
<?php

test(...[], a: 42);
function test(...$args) {
var_dump($args);
}

test(...[1, 2], a: 3);
test(...[1, 'a' => 2], b: 3);

function test2($a, $b, $c = 3, $d = 4) {
var_dump($a, $b, $c, $d);
}

test2(...[1, 2], d: 40);
test2(...['b' => 2, 'a' => 1], d: 40);

try {
test2(...[1, 2], b: 20);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
test2(...[1, 'b' => 2], b: 20);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

?>
--EXPECTF--
Fatal error: Cannot combine named arguments and argument unpacking in %s on line %d
--EXPECT--
array(3) {
[0]=>
int(1)
[1]=>
int(2)
["a"]=>
int(3)
}
array(3) {
[0]=>
int(1)
["a"]=>
int(2)
["b"]=>
int(3)
}
int(1)
int(2)
int(3)
int(40)
int(1)
int(2)
int(3)
int(40)
Named parameter $b overwrites previous argument
Named parameter $b overwrites previous argument
4 changes: 2 additions & 2 deletions Zend/tests/named_params/unpack_and_named_2.phpt
@@ -1,10 +1,10 @@
--TEST--
Mixing unpacking and named params (2)
Named args before unpacking (not supported)
--FILE--
<?php

test(a: 42, ...[]);

?>
--EXPECTF--
Fatal error: Cannot combine named arguments and argument unpacking in %s on line %d
Fatal error: Cannot use argument unpacking after named arguments in %s on line %d
9 changes: 2 additions & 7 deletions Zend/zend_compile.c
Expand Up @@ -3472,7 +3472,7 @@ uint32_t zend_compile_args(
if (arg->kind == ZEND_AST_UNPACK) {
if (uses_named_args) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking");
"Cannot use argument unpacking after named arguments");
}

uses_arg_unpack = 1;
Expand All @@ -3492,16 +3492,11 @@ uint32_t zend_compile_args(
}

if (arg->kind == ZEND_AST_NAMED_ARG) {
if (uses_arg_unpack) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot combine named arguments and argument unpacking");
}

uses_named_args = 1;
arg_name = zval_make_interned_string(zend_ast_get_zval(arg->child[0]));
arg = arg->child[1];

if (fbc) {
if (fbc && !uses_arg_unpack) {
arg_num = zend_get_arg_num(fbc, arg_name);
if (arg_num == arg_count + 1 && !may_have_undef) {
/* Using named arguments, but passing in order. */
Expand Down

0 comments on commit 1c08f8a

Please sign in to comment.