One of PHP’s most powerful data types is the array. It can hold numbers, it can hold letters, it can be sorted, sliced and chunked. Speaking of sorting, when sorting an array the straight forward sorting functions are only for sorting by the keys or by the values. What about when you have an array of arrays and want to sort be a specific key in the array? That’s where usort() comes in. First, let’s get our array set up:

$array = array(
    array('name' => 'Bob',    'weight' => 200),
    array('name' => 'Rachel', 'weight' => 145),
    array('name' => 'Arthur', 'weight' => 160),
    array('name' => 'Paige',  'weight' => 120),
    array('name' => 'Chris',  'weight' => 135),
);

The array above is comprised of arrays that hold the name of a person and their weight. It’s mixed up on purpose so we can sort it.

To use usort() we either need to create a function or use an anonymous function that’s passed it at run time. I’m opting to use separate functions for the examples but will elaborate on how to make an awesome function that’s reusable for any field. To start, let’s create 2 functions, 1 to sort by name and one to sort by weight:

function sortByName($a, $b)
{
    $a = $a['name'];
    $b = $b['name'];

    if ($a == $b) return 0;
    return ($a < $b) ? -1 : 1;
}

function sortByWeight($a, $b)
{
    $a = $a['weight'];
    $b = $b['weight'];

    if ($a == $b) return 0;
    return ($a < $b) ? -1 : 1;
}

Why would we need two functions? Well because usort() only passes in 2 arguments to the function, there’s no way to define a single function that can filter by different rows outside of a using a global variable that the functions would have access to. That would get messy pretty quick in my opinion.

So now that we have our functions define, we can use usort() to sort the array by either of the fields like this:

usort($array, 'sortByName');
usort($array, 'sortByWeight');

The array is passed in as a reference so the array itself has it’s elements sorted, no new array is created.

Now that we know how usort() works, let’s address the obvious shortcoming. You could end up creating a whole lot of sort functions to sort by all the different fields you may want to sort by, and even get into more functions to support sorting in descending order instead of ascending. With the power of anonymous functions with create_function() (available since PHP 4.0.1) we can create a single function that we can pass our array to and sort by a specific field. To take it a step further, we can even use an optional argument to determine the direction of the sort:

function sortBy($field, &$array, $direction = 'asc')
{
    usort($array, create_function('$a, $b', '
        $a = $a["' . $field . '"];
        $b = $b["' . $field . '"];

        if ($a == $b) return 0;

        $direction = strtolower(trim($direction));

        return ($a ' . ($direction == 'desc' ? '>' : '<') .' $b) ? -1 : 1;
    '));

    return true;
}

What create_function() allows us to do is generate our sort function on the fly. Because it’s anonymous, it won’t conflict with any other named functions in your code, so that’s not a worry either. The option $direction argument takes the value of “asc” or “desc” and sorts accordingly. Now we have a single function that can be used to sort both by name and by weight with our original array and the array is passed by reference so it retains the same interfacing as usort() already provides. You can now sort like this:

sortBy('name',   $array);
sortBy('weight', $array);

And if you wanted to sort in the opposite order:

sortBy('name',   $array, 'desc');
sortBy('weight', $array, 'desc');

The only real shortcoming of this is that the code doesn’t sanity check if the field exists. This usually isn’t an issue as most data being pulled out of a database would have all the columns even if they didn’t have a value.

This function was adapted from the logic of the Sort class in the PHP framework PICKLES. PICKLES is a PHP framework written by myself (Josh Sherman, the author of this blog) and has been in development for 8 or so years now. The focus of the framework is to give the developer more liberties by doing less while providing a solid foundation to build websites and being highly extendable.

Pardon the shameless self promotion ;)