PHP 8中的名为Arguments和Variadic

PHP 8.0介绍命名参数。这是当前位置语法的扩展。命名参数删除了一些限制。它还现代化了用途任意数量的参数的方法,使用传播操作员。让’S看那里发生了什么。

快速查看命名参数

直到最后的7.x版本,PHP仅使用位置参数。在方法签名中,第一个位置处的参数被分配给第一个位置的参数。然后填充任何缺少的参数,填充了默认值。最后,删除了多余的参数,或者向缺少缺少参数的消息来提升消息。

 
<?php

function foo($a, $b = 1) { echo "$a / $b\n"; }

// Not enough parameter 
foo();

// Enough parameters 
foo(1); foo(1, 2);

// Too many parameters 
foo(1, 2, 3);

?>

问题出现了可选参数。特别是当他们中有许多并且他们都是独立的。位置参数施加在使用默认值之前提供所有参数,因此可以跳过。必须设置一个选项后,它符合参数列表的末尾,必须填充所有先前的值。

 
<?php

function foo($a = 0, $b = 1) {}

// Default behavior foo();

// Set to 1-1 
foo(1);

// Set to 1-0, so inverted 
foo(1, 0);

// Set to b = 2, don't change a. 
foo( 0 /* default would be good */, 2);

?> 

在本机PHP中,它发生在setcookie(),mail()或json等函数解码()。有时,问题是跳过专用选项功能,如会话start()和一个选项数组。

对于那些函数,参数列表很长:频繁地,我们,编码器,必须依靠文档来了解必须传递哪个参数。实际上,不仅必须知道目标参数,而且还有所有先前的参数,以便以正确的默认值填充它们。

命名参数

命名参数通过向每个参数提供名称来解决此问题。实际上,他们已经有一个名称,因为签名为每个参数分配了不同的名称。这不是这种情况,直到一些不那么最近的版本,但现在在Linting Time强制执行它。

The call syntax changes a little, to accommodate the target name. It is the name of the argument in the signature, without the classic $ dollar sign. Be aware that they are case sensitive.

 
<?php

function foo($a = 0, $b = 1) {}

// Default behavior foo();

// Set to 1-0 
foo(a: 1);

// Set to 1-2 
foo(a: 1, b: 2);

// Set to b = 3 
foo( b: 3);

?> 

从现在开始,参数由他们的名字标识,而不是他们的立场。因此,可以将值分配给右参数,并且调用顺序可以与方法签名不同。

As you can see, the name of the argument is a kind of in-the-code documentation. This makes the 7th argument of setcookie() obvious : it is httponly.

命名参数和传播操作员

The spread operator is the opposite of the variadic. They share the same syntax : ... and they have opposite effects. In a signature, ... means that all remaining arguments are collected in an array, while in a methodcall, it means that all elements of the array are used, respective of their position in the array.

此PHP 8.0代码说明了该功能。

 
<?php

function foo($a = 0, $b = 1) {}

// Set to 1-1 foo(...[1, 1]);

// Set to 1-1 foo(...[4 => 1, 1]);

// Set to 1-2 
foo(...['a' => 1, 'b' => 2]);

// An error, as $a receives the whole array. Typehint this! 
foo([1, 2]);

?>
 

如您所见,可能的两个阵列语法:位置和命名参数。让’s review them both.

位置参数使用整数索引,特别是自动生成的索引。如果填充数组而不提及索引,则PHP自动生成索引,从0开始启动索引(此代周围有一些微妙之处,因此请检查文档 阵列 )。

位置参数和索引顺序

位置参数基于简单的PHP阵列。它很简单:阵列的第n个元素在该方法中给出第n个参数。

 
<?php

function foo($a, $b, $c) { print "$a-$b-$c\n"; }

// Set to 0-1-2 
foo(...range(0, 2));

// Set to 0-1-2 
foo(...array(4 => 0, 1, 2));

?> 

它还意味着阵列中的索引不是参数的位置。正如您在上面的那样,当数组’S索引开始于4,参数仍然以相同的顺序传递:0,1,2。PHP’T考虑到索引,但阵列中的元素的位置。这是他们在阵列中引入的方式。

让’稍微推动这个例子:

 
<?php

function foo($a, $b, $c) { print "$a-$b-$c\n"; }

// Set to 0-1-2 
foo(...array(4 => 0, -3 => 1, 12 => 2));

// Set to 1-0-2 
$x = array(4 => 0, -3 => 1, 12 => 2); 
ksort($x); 
foo(...$x);

?>
 

参数的顺序保持不变,无论阵列中的索引的实际顺序如何。当然,我们可以使用索引顺序来调用数组上的ksort(),以在呼叫中使用它之前更改位置。这样,PHP根据任意顺序重新排序元素,然后使用该数组作为参数。

php使用的实际顺序是可用array_values()可用的顺序。这是一个微妙的区别,特别是当用算法构建参数列表时。这样做时,建议保持一致的方法来填充数组,或者使用索引在呼叫之前对参数进行排序。

传播哈希,仅用于参数

当然,排序的最佳方法是通过使用命名的参数来让PHP执行。由于您可能在第一个示例中注意到,可以使用哈希来实现参数。

Hashes are also called maps, in other languages. It is the version of the PHP array, which uses strings as index. Here, hashes are just what we need to provide the names of the arguments, and their value. So, it was adapted to PHP 8.0, for calling named argument. Be aware that it is not possible to use ... with hashes in arrays.

 
<?php

function foo($a, $b) { print "$a-$b\n"; }

// Set to 1-2 
foo(...[1, 2]);

// Set to 1-2 
foo(...['a' => 1, 'b' => 2]);

// Set to 1-2 
foo(...['b' => 2, 'a' => 1]);

//Fatal error: Cannot unpack array with string keys 
[...[1, 2, 'd' => 2], [4]];

?> 

Back to the named arguments. As long as the string index match the arguments, everything is fine. Just remember to drop the $ in the index name, as it is not needed.

Extra arguments are signaled with a Fatal Error : Unknown named parameter $d. Missing arguments are filled with their default value, when available, then signaled with an error too : Too few arguments to function foo().

所有的经典。接下来是新的。

休闲哈希!

哈希匹配非常紧密参数传递方法。所有名称在哈希索引中都是唯一的,就像方法一样’s arguments. No double ['a' => 1, 'a' => 2], as PHP silently overwrites the first with the second.

An interesting segue is the question of the variadic operator. Since, multiple indexes are not possible, a then natural solution is to consolidate all the values of one argument in an array. After all, this is what the ... operator does, when it is used in the method signature.

 
<?php

function foo($a, ...$b) { print_r($b); }

foo(3, 4); foo(...[2, 'b' => [2, 3]]);

?> 
Array
(
    [0] => 4
)
Array
(
    [b] => Array
        (
            [0] => 2
            [1] => 3
        )

)

呼叫之间存在2个细微差别:首先,收到的参数根据调用语法而改变其形状。

The first call is the hardcoded version. Upon reception, $b is an array, with one element : 4. This is expected. Adding a third argument to the call will add this value after the 4.

The second call is the positional dynamic version. Upon reception, $b is now an array of array, and the actual arguments are at index [0]. This is backward compatible with PHP 7.2, which is also behaving like that. Still, this means that the way to call a method may have an impact on the format of the received arguments.

现在命名的变量论点

PHP 8.0引入了一个新的变化:结果数组现在也是一个哈希。它不是数组,其中整数是索引。它是一个哈希,其中唯一索引的名称是参数的名称。

 
<?php
function foo($a, ...$b) { print_r($b); }

foo(...[2, [2, 3]]); foo(...[2, 'b' => [2, 3]]);

?>
 
Array
(
    [b] => 1
)
Array
(
    [b] => Array
        (
            [0] => 2
            [1] => 3
        )

)

The index 0 has become the index b. This letter is the name of the argument, and it doesn’t change with the calling syntax. This time, it is a backward incompatible change : the code that fetch the argument value must access the index b and not 0.

一个修复它是在传入参数上应用array_values(),以回归以前的行为。否则,可以使用其他数组通过array_merge()来合并该参数,并且密钥将在应用程序上旅行。 array_merge()和一些其他php本机函数,保留键。

名为Arguments和Variadic

命名参数在PHP 8.0中是新的,他们已经对我们的代码产生了影响。而不是使用选项数组,现在可以将它们全部包含在方法签名中,并根据需要跳过它们。这绝对是一个改善。落后不兼容,如索引参数的索引,将需要一些适应性。

提供可读的参数名称会发生​​其他影响。到目前为止,参数名称仅限于该方法’s王牌,他们没有看不见。使用PHP 8.0,重要的是向参数提供有意义的名称,因此它们可以充当文档,并且很容易记住。

通过在代码库上运行exakat,您可以为PHP 8.0做好准备。以下是一些推荐的阅读:

  • 参数名称 报告,列出了应用程序中的所有参数,其中包含其类型和值,用于检查拼写,含义和一致性
  • 命名参数Variadic.,根据他们进入PHP 8.0时检查变形参数的规则
  • 不匹配参数名称,检查参数名称是否在类别扩展和接口实现中同步的规则
  • 交换争论,一个规则检查参数在覆盖方法之间交换其位置时检查。

谢谢 Ciaran McNulty 为了发现很多人,同时在Behat工作时’s PHP 8.0 version.