Collection::sortByDesc
Orders a collection by a field or computed value from highest to lowest.
Collection::sortByDesc(array|callable|string $callback, int $options = SORT_REGULAR): staticParameters
| Parameter | Type | Description |
|---|---|---|
$$callback | array|callable|string | A field name or dot path, a closure invoked as ($item, $key) returning the value to sort on, or an array of sort operations. Every direction in that array is forced to 'desc'. |
$$optionsoptional | int= SORT_REGULAR | A PHP sort flag such as SORT_NATURAL, SORT_STRING or SORT_NUMERIC applied to the comparison. |
Return value
staticA new collection ordered by the resolved values in descending order, with the original keys preserved.
Changelog
- PHP 8.xAn array of sort operations may be passed, but every direction in it is rewritten to 'desc' before the sort runs.
Identical to sortBy() in every way except direction — same string, dot path and closure forms, same data_get() resolution, same preserved keys. Internally it just calls sortBy($callback, $options, true).
Reach for it for leaderboards, newest-first feeds, most-expensive-first tables: anything where the interesting end of the data is the top. Combined with values()->slice(0, 3) it is the standard way to take a top-N out of an in-memory set.
The array form is a trap
Given an array of sort operations, this method rewrites every direction to 'desc' before delegating. So sortByDesc([['name', 'asc'], ['age', 'desc']]) does not sort names ascending — it sorts both descending, silently discarding what you wrote. For genuine mixed-direction sorting, always call sortBy() and put the direction in each pair. Comparator closures inside the array are unaffected, because their direction lives in the order of $a and $b, so they are not reversed either.
As with every sort here, keys travel with their items; chain values() before serializing or indexing by position.
Example
When to use it
- Build a leaderboard ordered by score, highest first.
- Show the most recently updated records at the top of an already-loaded collection.
- Order products by price high to low, then take the top three.
Frequently asked questions
Why is sortByDesc ignoring the 'asc' in my sort array?
Because sortByDesc rewrites every direction in a multi-sort array to 'desc' before running. Use sortBy() with explicit directions in each pair when you need mixed directions.
What is the difference between sortByDesc and sortDesc?
sortByDesc orders by a field, dot path or closure, while sortDesc compares the items themselves. Use sortDesc only on flat collections of scalars.
Is sortByDesc the same as sortBy()->reverse()?
Not quite — reversing a sorted collection also flips the relative order of items that compare equal, whereas sortByDesc keeps stable ties. It also does an extra pass over the data.
More examples
The array form forces every direction to desc
The first call prints Taylor 34, Abigail 32, Abigail 30 — both fields descending, because sortByDesc rewrites each pair's direction to 'desc'. The second prints Abigail 32, Abigail 30, Taylor 34, which is the name-ascending, age-descending order the first call appeared to ask for.
<?php
$people = collect([
['name' => 'Abigail', 'age' => 30],
['name' => 'Taylor', 'age' => 34],
['name' => 'Abigail', 'age' => 32],
]);
// The 'asc' you wrote is thrown away.
print_r($people->sortByDesc([['name', 'asc'], ['age', 'asc']])->values()->all());
// Do this instead for a genuinely mixed sort.
print_r($people->sortBy([['name', 'asc'], ['age', 'desc']])->values()->all());Top N from an in-memory collection
Prints 1. Linus 94, 2. Grace 88, 3. Ada 71. values() sits between the sort and the take so the loop key doubles as the rank — without it the keys would still be 1, 2, 0 from the original array.
<?php
$scores = collect([
['player' => 'Ada', 'points' => 71],
['player' => 'Linus', 'points' => 94],
['player' => 'Grace', 'points' => 88],
['player' => 'Alan', 'points' => 62],
]);
$top = $scores->sortByDesc('points')->values()->take(3);
foreach ($top as $rank => $row) {
echo ($rank + 1) . ". {$row['player']} {$row['points']}" . PHP_EOL;
}In an application: newest first by a date attribute
Sorting by a relation count is the case where an in-memory sort earns its keep — the database has no such column without a withCount(). Carbon instances implement comparison, so sorting on a date cast works with the plain field name.
<?php
namespace App\Http\Controllers;
use App\Models\Project;
class DashboardController extends Controller
{
public function index()
{
$projects = Project::with('tasks')->get();
return view('dashboard', [
// Sort by a related aggregate that SQL did not compute.
'busiest' => $projects->sortByDesc(fn (Project $p) => $p->tasks->count())->values(),
// Carbon instances compare correctly with <=>.
'recent' => $projects->sortByDesc('updated_at')->values()->take(5),
]);
}
}
Discussion