Splatpacking 与 array_values() 使用数字键重新索引数组

Splatpacking versus array_values() to re-index an array with numeric keys

从 PHP7.4 开始,有一种新的技术可以使用数字键重新索引数组。

我将其称为“数组重新打包”或者类似“splatpacking”这样有趣的名称。简单的过程涉及使用 splat 运算符(...)——又名 "spread operator"——解压缩一个数组,然后通过 "symmetric array destructuring".[=24 用第一级元素填充一个新数组=]

比较码:(Demo)

$array = [2 => 4, 5 => 3, "3" => null, -10.9 => 'foo'];

var_export(array_values($array));
var_export([...$array]);

两者都会输出:

array (
  0 => 4,
  1 => 3,
  2 => NULL,
  3 => 'foo',
)

同样,splatpacking 技术严格限于具有数字键的数组,因为 splat 运算符会阻塞任何其他内容,并且只有 PHP7.4 才能将解压后的值直接写入数组,并且更高。

由于这两种技术在排位赛中提供相同的输出,我什么时候应该使用一种而不是另一种?

请注意,这不是关于如何重新索引键,而是 array_values() 与新可用技术的比较。

这不同于:

以及其他几十个询问如何重新索引数组的旧页面。

重新索引第一个元素未设置的 450,000 元素数组时...

array_values() 始终是 splatpacking 的两倍。

$array = range(0, 450000);
unset($array[0]);

Benchmark script

示例输出:

Duration of array_values: 15.328378677368
Duration of splat-pack: 29.623107910156

在性能方面,您应该始终使用array_values()。这是函数调用技术比非函数调用技术更有效的一种情况。


我想 splatpacking 技术获胜的唯一场景是如果你是 CodeGolfer -- 13 个字符对 5 个字符。

这两种方法之间存在性能差异(如), but this is not the main difference between these two approaches. After all you should remember the famous quote:

所示

premature optimization is the root of all evil - DONALD E. KNUTH

可能会在下一个 PHP 版本中对 splat 运算符进行一些性能优化,它会比 array_values() 更快。除非你真的需要从你的代码中挤出最大的性能,否则我建议不要担心重新索引数百万个值所花费的时间。相反,让我们考虑一下这两种方法的共同点或不同点。

  1. Splat 运算符只能用于数字索引。如果您的数组包含字符串键(即使是空字符串),那么 splat 运算符将阻塞并抛出异常:

    Fatal error: Uncaught Error: Cannot unpack array with string keys

    如果你想用数字索引重新索引你的数组,那么更安全的选择是使用 array_values()。它适用于数值数组和关联数组。

  2. 在某些情况下,您可能需要将 array_value 作为回调传递。如果你想对 splat 运算符做同样的事情,你需要将它包装在闭包中,例如fn($arr) => [...$arr]。使用 'array_values' 可能是一个更简单、更清晰的解决方案。例如,如果你想重新索引多维数组(只有数字键),你有以下两个选择:

    $array = [range(0, 10), range(15,25)];
    unset($array[0][1], $array[1][5]);
    
    $reindex_array = array_map('array_values', $array);
    // or
    $reindex_array = array_map(fn($arr) => [...$arr], $array);
    

    当然,这完全取决于您,您更喜欢哪种方法。

  3. array_values() 不适用于 generators/iterators。如果您想解压一个生成器,您可以使用 splat 运算符。例如:

    function arrGen() {
        for($i = 11; $i < 15; $i++) {
            yield $i**2 => $i;
        }
    }
    
    $it = arrGen();
    $reindexed_array = [...$it];
    
  4. Splat 运算符方式不仅允许您重新索引数组,还可以在前面或附加额外的值。您也可以将两个数组合并为 1。它比 array_values() 更健壮。例如:

    $arr = ['someValue', 2=> 'Not 2', 3];
    $r1 = ['I am number 1!', ...$arr];
    
    var_dump($r1);
    

一种方法胜过另一种方法的情况可能更多。最后,由开发人员根据具体情况决定何时使用哪个选项。