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.

1
  • This question is missing its minimal reproducible example and does make a good canonical question for this topic. Commented May 17, 2022 at 10:17

11 Answers 11

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

Sign up to request clarification or add additional context in comments.

5 Comments

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.
Now now, that would make PHP be sensible and usable, can't have that can we? :)
No we can't, but we really need another way to express the same expression in PHP7 though wiki.php.net/rfc/combined-comparison-operator
Typical, stealing a perl feature and then implementing it wrong.
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.

1 Comment

What if $a->$prop == $b->$prop?
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 );

1 Comment

@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.
4

For that compare function, you can just do:

function cmp( $a, $b )
{ 
    return $b->weight - $a->weight;
} 

1 Comment

for information, this works only for numeric values. Also note that a comparison function "should" return -1, 0 or 1.
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.

Comments

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;
    }
}

Comments

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:

Comments

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

1 Comment

Why don't return $tmpArray? What is the need of copy $tmpArray into $sortedArray ?
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'));

Comments

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:

Comments

-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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.