PHP 7新特性五 Spread operator(数组延展操作符)
在数组表达式中对展开操作符(Spread Operator)支持的 RFC 投票是 绝大多数人赞同 将此功能添加到 PHP 7.4。
扩展运算符支持参数解包首先存在于 PHP 5.6 中,并且此 RFC 扩展了对数组的使用;扩展可以支持 Traversable 的数组和对象。这是 RFC 的一个基本示例:
$parts = ['apple', 'pear']; $fruits = ['banana', 'orange', ...$parts, 'watermelon'];// ['banana', 'orange', 'apple', 'pear', 'watermelon']; /*以下是进一步的示例:*/ $arr1 = [1, 2, 3]; $arr2 = [...$arr1]; // [1, 2, 3] $arr3 = [0, ...$arr1]; // [0, 1, 2, 3] $arr4 = array(...$arr1, ...$arr2, 111); // [1, 2, 3, 1, 2, 3, 111] $arr5 = [...$arr1, ...$arr1]; // [1, 2, 3, 1, 2, 3] //定义函数 function getArr() { return ['a', 'b']; } $arr6 = [...getArr(), 'c']; // ['a', 'b', 'c'] $arr7 = [...new ArrayIterator(['a', 'b', 'c'])]; // ['a', 'b', 'c'] function arrGen() { for($i = 11; $i < 15; $i++) { yield $i; } } $arr8 = [...arrGen()]; // [11, 12, 13, 14]
函数调用中带有前缀的参数...将是“unpacked”:不是将参数本身传递给函数,而是传递它包含的元素(作为单独的参数)。这适用于数组和Traversables。
因此,以下所有函数调用都是等效的:
function test(...$args) { var_dump($args); } test(1, 2, 3); // [1, 2, 3] test(...[1, 2, 3]); // [1, 2, 3] test(...new ArrayIterator([1, 2, 3])); // [1, 2, 3] /*注意:解压缩像[1,2,3]这样的常量数组并没有多大意义。 通常这些会解压一些变量,比如... $ args*/ //可以...在调用中多次使用,并且可以在参数解包前使用普通参数: $args1 = [1, 2, 3]; $args2 = [4, 5, 6]; test(...$args1, ...$args2); // [1, 2, 3, 4, 5, 6] test(1, 2, 3, ...$args2); // [1, 2, 3, 4, 5, 6] //但是,在使用参数解包后,不可能使用普通参数。以下两个都是无效的: //该...操作适用于所有的参数列表,包括new表达式: fn(...$args); $fn(...$args); $obj->fn(...$args); ClassName::fn(...$args); new ClassName(...$args); //参数解包不仅限于可变参数函数,它还可以用于“普通”函数: function test($arg1, $arg2, $arg3 = null) { var_dump($arg1, $arg2, $arg3); } test(...[1, 2]); // 1, 2 test(...[1, 2, 3]); // 1, 2, 3 test(...[1, 2, 3, 4]); // 1, 2, 3 (函数声明未捕获剩余的arg)
为了确保与命名参数的向前兼容性,解包操作符不支持字符串键。如果在解包期间遇到字符串键,则抛出可恢复的错误。如果使用自定义错误处理程序忽略错误,则不会解压缩其他参数,但仍会发生调用。
优于call_user_func_array的优点
call_user_func_array如果您还需要传递固定参数,则 使用会变得复杂。相比:
call_user_func_array([$db, 'query'], array_merge(array($query), $params)); // 对比 $db->query($query, ...$params);
call_user_func_array需要回调。因此,即使已知被调用的函数/方法,您仍然需要使用动态字符串/数组回调。这通常会排除任何IDE支持。
(new ReflectionClass('ClassName'))->newInstanceArgs($args); // 对比 new ClassName(...$args);
call_user_func_array不适用于构造函数。而是ReflectionClass::newInstanceArgs()必须使用:
Futhermore call_user_func_array具有相当大的性能影响。如果大量的呼叫通过它,这可能会产生显着的差异。出于这个原因,项目1)经常用call_user_func_array以下形式的switch语句替换特别常见的调用:
switch (count($args)) { case 0: $func(); break; case 1: $func($args[0]); break; case 2: $func($args[0], $args[1]); break; case 3: $func($args[0], $args[1], $args[2]); break; case 4: $func($args[0], $args[1], $args[2], $args[3]); break; case 5: $func($args[0], $args[1], $args[2], $args[3], $args[4]); break; default: call_user_func_array($func, $args); break; }
该...参数拆包语法比快约3.5至4倍call_user_func_args。这解决了性能问题。基准代码和结果。
最后,如果存在可变参数语法,人们自然希望这种语法存在。因此,如果我们实现可变参数,那么最好也包括它。
PHP 7新特性五 Spread operator(数组延展操作符):https://www.yzdlm.com/php/29.html
作者:大脸猫 分类: 大脸猫PHP博客
上一篇:生气时还能保持冷静的人不会太差~~~ 下一篇:【百度站长活动 6.4-6.14】答题送好礼,回帖就给发奖励【已结算】