phpsortingmultidimensional-arrayarray-multisort

array_multisort() with a variable/dynamic number of parameters does not affect the original array


I'm using array_multisort (PHP 7.4) to apply a mutli-dimensional sort. I think I'm using it correctly, but the result is not what I would expect. No matter what direction I set, it only sorts ascending (even if I set both to SORT_DESC). I tried different sort flags (e.g. SORT_STRING, SORT_NATURAL), but this did not make a difference.

$definitions = [
  [
    'name' => 'Bart',
    'age' => 12,
    'location' => 'Brazil',
  ],
  [
    'name' => 'Daniel',
    'age' => 51,
    'location' => 'Brazil',
  ],
  [
    'name' => 'Adam',
    'age' => 33,
    'location' => 'France',
  ],
  [
    'name' => 'Adam',
    'age' => 44,
    'location' => 'France',
  ],
  [
    'name' => 'Adam',
    'age' => 5,
    'location' => 'France',
  ],
  [
    'name' => 'Zed',
    'age' => 21,
    'location' => 'GB',
  ],
];

$sorting = [
  [
    'field' => 'name',
    'direction' => SORT_ASC,
  ],
  [
    'field' => 'age',
    'direction' => SORT_DESC,
  ]
];


$sort_args = [];
foreach ($sorting as $sort) {
  $sort_args[] = array_column($definitions, $sort['field']);
  $sort_args[] = $sort['direction'];
  $sort_args[] = SORT_REGULAR;
}
array_multisort($definitions, ...$sort_args);

The result:

array (
  0 =>
    array (
      'name' => 'Adam',
      'age' => 5,
      'location' => 'France',
    ),
  1 =>
    array (
      'name' => 'Adam',
      'age' => 33,
      'location' => 'France',
    ),
  2 =>
    array (
      'name' => 'Adam',
      'age' => 44,
      'location' => 'France',
    ),
  3 =>
    array (
      'name' => 'Bart',
      'age' => 12,
      'location' => 'Brazil',
    ),
  4 =>
    array (
      'name' => 'Daniel',
      'age' => 51,
      'location' => 'Brazil',
    ),
  5 =>
    array (
      'name' => 'Zed',
      'age' => 21,
      'location' => 'GB',
    ),
)

What I expected:

array (
  0 =>
    array (
      'name' => 'Adam',
      'age' => 44,
      'location' => 'France',
    ),
  1 =>
    array (
      'name' => 'Adam',
      'age' => 33,
      'location' => 'France',
    ),
  2 =>
    array (
      'name' => 'Adam',
      'age' => 5,
      'location' => 'France',
    ),
  3 =>
    array (
      'name' => 'Bart',
      'age' => 12,
      'location' => 'Brazil',
    ),
  4 =>
    array (
      'name' => 'Daniel',
      'age' => 51,
      'location' => 'Brazil',
    ),
  5 =>
    array (
      'name' => 'Zed',
      'age' => 21,
      'location' => 'GB',
    ),
)

Am I missing something or is this busted?


Solution

  • You have the arguments in the wrong order. The array you wish to sort should be the last item for this type of sorting.

    Example #3: https://www.php.net/manual/en/function.array-multisort.php#example-5040

    You may have done this so that you can use the spread operator (which is fine). If you want to continue using the spread operator you would adjust your code as so:

    $sort_args[] = &$definitions; // add this line
    array_multisort(...$sort_args); // remove `$definitions` from this line
    

    Note that we are passing $definitions as reference otherwise when we push it to $sort_args, we would be creating a copy (due to the nature of PHP).

    Without passing by reference, that original array won't be sorted, only the copy we created.