-4

As of PHP7.4, there is a newly available technique to re-index an array with numeric keys.

I'll call it "array re-packing" or maybe something fun like "splatpacking". The simple process involves using the splat operator (...) -- aka "spread operator" -- to unpack an array then filling a new array with the first-level elements via "symmetric array destructuring".

Comparison Code: (Demo)

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

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

Both will output:

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

Again, the splatpacking technique is strictly limited to arrays with numeric keys because the splat operator chokes on anything else AND the ability to write the unpacked values directly into an array is only available from PHP7.4 and higher.

With the two techinques delivering the same output in qualifying situations, when should I use one over the other?

Note, this is not about how to reindex keys, but a comparison of array_values() versus a newly available technique.

This is different from:

and the other tens of old pages that ask how to reindex an array.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • 2
    I see this as one of the more interesting PHP questions in a while, especially since it isn't framework specific. It leaves me curious what splatpacking is for if it's always slower. Syntax sugar only? Consistency with other languages that have adopted the spread operator? – Josh Rumbut Aug 31 '19 at 07:14

2 Answers2

8

There is a performance difference between these two methods (as shown in the other answer), 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

It could be that in the next PHP release the splat operator gets some performance optimization and it will be faster than array_values(). Unless you really need to squeeze out the most performance from your code, I would recommend to not worry about the time it takes to re-index millions of values. Instead let's consider what both of these approaches have in common or don't.

  1. Prior to PHP 8.1, splat operator can only work with numerical indices. If your array contains a string key (even an empty string) then splat operator will choke and throw an exception:

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

    If you would like to re-index your array with numerical indices, then the safer option is to use array_values(). It works for both numerical and associative arrays.

  2. There might be situations when you need to pass array_value as a callback. If you wanted to do the same with the splat operator you would need to wrap it in closure e.g. fn($arr) => [...$arr]. Using 'array_values' instead could be a simpler and cleaner solution. For example if you wanted to re-index multi-dimensional array (having only numerical keys) you have these two options:

     $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);
    

    Of course it's really up to you, which approach you prefer.

  3. array_values() does not work with generators/iterators. If you would like to unpack a generator you can use the splat operator instead. For example:

     function arrGen() {
         for($i = 11; $i < 15; $i++) {
             yield $i**2 => $i;
         }
     }
    
     $it = arrGen();
     $reindexed_array = [...$it];
    
  4. Splat operator way allows you not only to re-index the array, but also prepend or append extra values. You could also merge two arrays into 1. It is more robust than array_values(). For example:

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

There's probably more scenarios where one approach wins over the other. In the end it is up to the developer to decide when to use which option, based on the circumstances.

Dharman
  • 30,962
  • 25
  • 85
  • 135
4

When re-indexing a 450,000 element array which has its first element unset...

array_values() is consistently twice as fast as splatpacking.

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

Benchmark script

Sample output:

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

In terms of performance, you should always use array_values(). This is one case when a function-calling technique is more efficient than a non-function-calling technique.


I suppose the only scenario where the splatpacking technique wins is if you are a CodeGolfer -- 13 characters versus 5.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136