How to Sort a Multi-Dimensional Array in PHP
In my previous post, we filtered and paginated a PHP array with Ajax. In this post we’ll extend that functionality to allow the user to also sort the results by either the product title or the price using PHP’s built-function, usort. See a working example of this tutorial here.
Prerequisites
- A basic understanding of PHP and PHP arrays.
- The previous project we worked on, found here.
The usort() function takes two parameters. The first must be the multi-dimensional array you wish to sort and the second requires a callback function which will compare the values. In its most simplest form, it will like the code below:
<?php
$my_array = array(
array(
'first_name' => 'Antonio',
'last_name' => 'Stark',
'age' => 51
),
array(
'first_name' => 'Thor',
'last_name' => 'Odinson',
'age' => 967
),
array(
'first_name' => 'Steve',
'last_name' => 'Rogers',
'age' => 93
),
)
function myFunctionToCallback($a, $b) {
return $a['age'] < $b['age'];
}
usort ( $my_array , 'myFunctionToCallback' );
// Will sort by oldest first
Include Sort Select Inputs
First we need some HTML that we’ll need to create the select drop downs. We just need to add the following HTML into the form we already have just before the submit button:
<span> Sort By </span>
<select name="sort-by" class="form-control form-control-sm">
<option value="title">Title</option>
<option value="price">Price</option
</select>
<select name="sort-order" class="form-control form-control-sm">
<option value="ASC">ASC</option>
<option value="DESC">DESC</option>
</select>
Now we have four more $_GET values we can query: “title”, “price”, “ASC” and “DESC”.
Add the Sort Query to the PHP
In the PHP we will write a function similar to the above one. This function will go right before we sliced the original $products array. We’re going to usort() the array before we use array_slice() to limit and offset it. We have to do it this way because if we don’t, each page in the pagination will only apply the sorting for the limit.
<?php
// Add this callback function
function sortByQuery($a, $b) {
$sort_by = isset($_GET['sort-by']) ? $_GET['sort-by'] : 'title';
$sort_order = isset($_GET['sort-order']) ? $_GET['sort-order'] : 'ASC';
if ($sort_order == 'DESC') {
return $a[$sort_by] < $b[$sort_by];
}
else {
return $a[$sort_by] > $b[$sort_by];
}
}
// And the usort
usort($products, 'sortByQuery');
// Before we slice the array
$paged_products = array_slice($products, $offset, $limit);
The callback function, sortByQuery(), needs to parameters, $a and $b that will refer to indexes in the array as usort() does its thing.
In the code above, in the callback function, I’m checking if we have $_GET parameters set for ‘sort-by’ and ‘sort-order’ and if they aren’t set I’m setting the default values as ‘title’ and ‘ASC’ respectively.
Next, if the user has requested to sort descending, I’m using the less than operator “<“ otherwise it will revert to the original ascending order using the more than operator “>”.
Add the callback function as a string (with the single quotes and no parentheses) into the usort function and you’re golden.
Done and Dusted
If you’ve followed on from the previous tutorial, you won’t have to do anything else. Remember, the JQuery function is grabbing all the parameters from the form, no matter how many new fields we add and the http_build_query() function in the pagination is doing the same, by keeping our current query parameters intact when we paginate.
Important Things to Consider When Sorting With usort()
If you’re sorting float value (ie, values that have decimal places eg. 19.95), PHP will cast these to integers. So 19.95 will become 20 and 0.26 will become 0. In my example, my prices are all saved as strings, not floats.
Multi-dimensional arrays with defined indexes will lose their keys. For example this array:
$my_array = array(
'Antonio' => array(
'first_name' => 'Antonio',
'last_name' => 'Stark',
'age' => 51
),
'Thor' => array(
'first_name' => 'Thor',
'last_name' => 'Odinson',
'age' => 967
),
'Steve' => array(
'first_name' => 'Steve',
'last_name' => 'Rogers',
'age' => 93
),
)
Will result in:
Array ( [0] => Array ( 'first_name' => 'Thor', 'last_name' => 'Odinson', 'age' => 967 ) [1] => Array( 'first_name' => 'Steve', 'last_name' => 'Rogers', 'age' => 93 ) [2] => Array( 'first_name' => 'Antonio', 'last_name' => 'Stark', 'age' => 51 ) )
As always, this way of sorting a multi-dimensional array in PHP may not be the best way but it’s my way and hopefully will help you when building your project. Let me know in the comments.
Is this still valid in 2024? Please let me know in the comments below.