43

What is an elegant way to sort objects in PHP? I would love to accomplish something similar to this.

$sortedObjectArary = sort($unsortedObjectArray, $Object->weight);

Basically specify the array I want to sort as well as the field I want to sort on. I looked into multidimensional array sorting and there might be something useful there, but I don't see anything elegant or obvious.

jW.
  • 9,280
  • 12
  • 46
  • 50

11 Answers11

73

Almost verbatim from the manual:

function compare_weights($a, $b) { 
    if($a->weight == $b->weight) {
        return 0;
    } 
    return ($a->weight < $b->weight) ? -1 : 1;
} 

usort($unsortedObjectArray, 'compare_weights');

If you want objects to be able to sort themselves, see example 3 here: http://php.net/usort

Kent Fredric
  • 56,416
  • 14
  • 107
  • 150
  • That third example is basically saying, "Sorry there is no standard way for an object to have a comparator, just write a `cmp_obj` static function in the object, and remember to call usort with that function." Okay, except that cmp_obj has no special meaning in PHP. Maybe that would be useful if PHP had something like Python's `__cmp__` function as standard, or Java's `implements Comparable` interface so it could sort and use `<`, `>`, comparators without digging into whatever that class's implementation wants the sort to be. Unfortunately it looks like this isn't changing in PHP7 either. – NoBugs Aug 17 '15 at 04:13
  • 1
    Now now, that would make PHP be sensible and usable, can't have that can we? :) – Kent Fredric Aug 17 '15 at 04:19
  • No we can't, but we really need another way to express the same expression in PHP7 though https://wiki.php.net/rfc/combined-comparison-operator – NoBugs Aug 17 '15 at 04:27
  • Typical, stealing a perl feature and then implementing it wrong. – Kent Fredric Aug 17 '15 at 04:38
  • http://php.net/manual/en/language.oop5.object-comparison.php # Oh... Why. Why! Why!. – Kent Fredric Aug 17 '15 at 05:14
20

For php >= 5.3

function osort(&$array, $prop)
{
    usort($array, function($a, $b) use ($prop) {
        return $a->$prop > $b->$prop ? 1 : -1;
    }); 
}

Note that this uses Anonymous functions / closures. Might find reviewing the php docs on that useful.

Will Shaver
  • 12,471
  • 5
  • 49
  • 64
5

You can even build the sorting behavior into the class you're sorting, if you want that level of control

class thingy
{
    public $prop1;
    public $prop2;

    static $sortKey;

    public function __construct( $prop1, $prop2 )
    {
        $this->prop1 = $prop1;
        $this->prop2 = $prop2;
    }

    public static function sorter( $a, $b )
    {
        return strcasecmp( $a->{self::$sortKey}, $b->{self::$sortKey} );
    }

    public static function sortByProp( &$collection, $prop )
    {
        self::$sortKey = $prop;
        usort( $collection, array( __CLASS__, 'sorter' ) );
    }

}

$thingies = array(
        new thingy( 'red', 'blue' )
    ,   new thingy( 'apple', 'orange' )
    ,   new thingy( 'black', 'white' )
    ,   new thingy( 'democrat', 'republican' )
);

print_r( $thingies );

thingy::sortByProp( $thingies, 'prop1' );

print_r( $thingies );

thingy::sortByProp( $thingies, 'prop2' );

print_r( $thingies );
Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
  • 19
    @Lobo PHP 5 was already 4 years old at the time I wrote this, which was now 4 years ago. I think after 8 years, we can safely put PHP4 out to pasture. – Peter Bailey Sep 22 '12 at 04:11
4

For that compare function, you can just do:

function cmp( $a, $b )
{ 
    return $b->weight - $a->weight;
} 
Tom
  • 41
  • 1
  • for information, this works only for numeric values. Also note that a comparison function "should" return `-1`, `0` or `1`. – Syscall Feb 20 '22 at 14:50
2

The usort function (http://uk.php.net/manual/en/function.usort.php) is your friend. Something like...

function objectWeightSort($lhs, $rhs)
{
   if ($lhs->weight == $rhs->weight)
     return 0;

   if ($lhs->weight > $rhs->weight)
     return 1;

   return -1;
}

usort($unsortedObjectArray, "objectWeightSort");

Note that any array keys will be lost.

Adam Wright
  • 48,938
  • 12
  • 131
  • 152
1

You could use the usort() function and make your own comparison function.

$sortedObjectArray = usort($unsortedObjectArray, 'sort_by_weight');

function sort_by_weight($a, $b) {
    if ($a->weight == $b->weight) {
        return 0;
    } else if ($a->weight < $b->weight) {
        return -1;
    } else {
        return 1;
    }
}
Paige Ruten
  • 172,675
  • 36
  • 177
  • 197
0
function PHPArrayObjectSorter($array,$sortBy,$direction='asc')
{
    $sortedArray=array();
    $tmpArray=array();
    foreach($this->$array as $obj)
    {
        $tmpArray[]=$obj->$sortBy;
    }
    if($direction=='asc'){
        asort($tmpArray);
    }else{
        arsort($tmpArray);
    }

    foreach($tmpArray as $k=>$tmp){
        $sortedArray[]=$array[$k];
    }

    return $sortedArray;

}

e.g =>

$myAscSortedArrayObject=PHPArrayObjectSorter($unsortedarray,$totalMarks,'asc');

$myDescSortedArrayObject=PHPArrayObjectSorter($unsortedarray,$totalMarks,'desc');
cHao
  • 84,970
  • 20
  • 145
  • 172
0

Depending on the problem you are trying to solve, you may also find the SPL interfaces useful. For example, implementing the ArrayAccess interface would allow you to access your class like an array. Also, implementing the SeekableIterator interface would let you loop through your object just like an array. This way you could sort your object just as if it were a simple array, having full control over the values it returns for a given key.

For more details:

Wilco
  • 32,754
  • 49
  • 128
  • 160
0

You can have almost the same code as you posted with sorted function from Nspl:

use function \nspl\a\sorted;
use function \nspl\op\propertyGetter;
use function \nspl\op\methodCaller;

// Sort by property value
$sortedByWeight = sorted($objects, propertyGetter('weight'));

// Or sort by result of method call
$sortedByWeight = sorted($objects, methodCaller('getWeight'));
Ihor Burlachenko
  • 4,689
  • 1
  • 26
  • 25
0

Update from 2022 - sort array of objects:

usort($array, fn(object $a, object $b): int => $a->weight <=> $b->weight);

Full example:

$array = [
    (object) ['weight' =>  5],
    (object) ['weight' => 10],
    (object) ['weight' =>  1],
];

usort($array, fn(object $a, object $b): int => $a->weight <=> $b->weight);
// Now, $array is sorted by objects' weight.

// display example :
echo json_encode($array);

Output:

[{"weight":1},{"weight":5},{"weight":10}]

Documentation links:

Syscall
  • 19,327
  • 10
  • 37
  • 52
-3

If you want to explore the full (terrifying) extent of lambda style functions in PHP, see: http://docs.php.net/manual/en/function.create-function.php

Internet Friend
  • 1,082
  • 7
  • 10