为什么…$args会给子数组增加值?PHP

为什么…$args会给子数组增加值?PHP,php,php-7,Php,Php 7,我正在使用…$args用参数填充我的函数,但是我遇到了一个奇怪的行为 我有两个测试功能: function withToken(...$arguments) { $params = []; $params['first'] = 'first'; if (count($arguments) > 0) { foreach ($arguments as $key => $value) { $params[$key] =

我正在使用
…$args
用参数填充我的函数,但是我遇到了一个奇怪的行为

我有两个测试功能:

function withToken(...$arguments)
{
    $params = [];

    $params['first'] = 'first';

    if (count($arguments) > 0) {

        foreach ($arguments as $key => $value) {

            $params[$key] = $value;

        }
    }

    return $params;
}

在我的脑海里,他们做同样的事情,那为什么要打电话呢

   withToken([
       'second' => 'second',
       'third' => 'third'
   ]);
返回

Array
(
    [first] => first
    [0] => Array
        (
            [second] => second
            [third] => third
        )

)
和呼唤

    normal([
       'second' => 'second',
       'third' => 'third'
    ]);
返回

Array
(
    [first] => first
    [second] => second
    [third] => third
 )

在PHP文档中,我没有找到任何关于它的信息,有人可以解释为什么会发生这种行为?

这与PHP如何传递参数有关。如果您转储第一个函数,您将得到

数组(1){[0]=>数组(2){[“第二”]=>字符串(6)“第二”[“第三”]=>字符串(5)“第三”}

它这样做的原因是告诉PHP接受一个可变数量的参数。数组参数仅计为一个参数

在第二个实例中,它作为数组本身传递。因为它是唯一的参数,PHP不需要转换数据

如果你想让它像写的那样工作,就这样做

call_user_func_array('withToken', [
   'second' => 'second',
   'third' => 'third'
]);

这是因为它将数组转换为单独的参数

您指定函数接受可变数量的参数:

function withToken(...$arguments)
但是,传递一个参数(数组)。这不会扩展为多个参数。您可以尝试解压缩:

withToken(...[
       'second' => 'second',
       'third' => 'third'
   ]);
无论你得到什么:

可捕获的致命错误:无法使用字符串键解包数组

这将起作用,但无法获得字符串键:

withToken(...[
       'second',
       'third'
   ]);
call_user_func_array('withToken', [
       'second' => 'second',
       'third' => 'third'
   ]);
与此相同(无字符串键):


如果需要字符串键和值,请坚持传递数组而不是可变数量的参数。

公认的答案解释了为什么会出现这种行为,但推荐的解决方案没有抓住要点:它建议您更改调用函数的方式。这完全是错误的:接受可变数量参数的函数应该相应地处理其参数,,以便可以像任何其他函数一样调用它

特别是,您知道您的
withToken()
函数接受数量可变的参数,所有这些参数都可以在列表
$arguments
中找到。因此,您只需正确扫描此列表:

function withToken(...$arguments)
{
    $params = [];
    $params['first'] = 'first';

    if (count($arguments) > 0) {
        $real_arg = $arguments[0]  

        foreach ($real_arg as $key => $value) {
            $params[$key] = $value;
        }
    }

    return $params;
}
使用此定义,您可以使用带有字符串键的数组调用函数,它的行为将符合您的预期:

   withToken([
   'second' => 'second',
   'third' => 'third'
  ]);
当然,这并不是使用可变数量的参数调用
withToken()
,而是使用一个参数(数组)。我的版本最多需要一个参数。如果
withToken()
被设计为与多个参数一起使用,您可以这样调用它:

withToken('second', 'third');

这些参数被收集到数组
$arguments
(必须使用数字索引)中,应该在函数的原始版本中使用循环进行处理

实际上,公认的答案建议,如果您需要字符串键和值,请坚持传递数组而不是可变数量的参数。在OP的示例中,似乎不需要可变数量的参数。是的,“…而不是可变数量的参数。”我的回答显示了可变数量参数功能是如何实现的。你是对的,OP示例中的参数数量没有变化(正如我在回答中也提到的),但OP正在尝试学习如何使用此功能。
withToken('second', 'third');