Collection::sortKeys

Orders an associative collection by its keys rather than by its values.

Signature
Collection::sortKeys(int $options = SORT_REGULAR, bool $descending = false): static

Parameters

ParameterTypeDescription
$$optionsoptionalint= SORT_REGULARA PHP sort flag such as SORT_NATURAL, SORT_STRING or SORT_FLAG_CASE, passed straight to ksort()/krsort().
$$descendingoptionalbool= falseSort keys from high to low. sortKeysDesc() is the shorthand for passing true here.

Return value

staticA new collection with the same key/value pairs, ordered by key.

A wrapper over ksort() (or krsort() when $descending is true) that leaves every pair intact and only changes their order. Values are never examined.

Reach for it whenever key order is observable: producing a stable JSON body so a snapshot test or an ETag does not churn, printing a configuration dump a human has to scan, or aligning two associative arrays before diffing them. It is also the fix for a groupBy() result, which comes out in first-encountered order rather than sorted.

What the flags change

Under the default SORT_REGULAR, string keys compare as strings, so item10 lands before item9. Pass SORT_NATURAL for the human ordering, and add SORT_FLAG_CASE to ignore case. Remember that PHP silently casts integer-like string keys to integers, so '10' is stored as 10 and sorts numerically no matter which flag you choose.

For key ordering that is not a simple comparison — a fixed schema order, say — sortKeysUsing() takes a comparator over the two keys. Sorting keys never touches the values, so a nested structure is unchanged one level down.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Produce a byte-stable JSON payload for snapshot tests or cache keys.
  • Order a groupBy() result, which otherwise follows first-encountered order.
  • Print a configuration or environment dump alphabetically for humans to scan.

Frequently asked questions

Why does item10 sort before item9?

Because the default SORT_REGULAR flag compares string keys character by character, and '1' precedes '9'. Pass SORT_NATURAL as the first argument to get the human ordering.

How do I sort keys in descending order?

Call sortKeysDesc(), or pass true as the second argument to sortKeys(). Both run krsort() under the hood.

Can I sort keys in an order that is not alphabetical?

Yes — sortKeysUsing() takes a comparator that receives the two keys, so you can rank them against a fixed list. sortKeys() itself only supports PHP's built-in sort flags.

More examples

Stable JSON for snapshots and cache keys

The first dump is bool(false) and the second bool(true): identical payloads only serialize identically once the keys are ordered. The final line prints {"alpha":1,"beta":2,"gamma":3}, which is what you want to hash for a cache key or store in a snapshot test.

Example · php
<?php

$a = collect(['beta' => 2, 'alpha' => 1, 'gamma' => 3]);
$b = collect(['gamma' => 3, 'alpha' => 1, 'beta' => 2]);

// Same data, different insertion order, different JSON.
var_dump(json_encode($a->all()) === json_encode($b->all()));

// Sorting the keys makes the encoding canonical.
var_dump(json_encode($a->sortKeys()->all()) === json_encode($b->sortKeys()->all()));

echo json_encode($a->sortKeys()->all()), PHP_EOL;

Numeric-like keys and custom key order

The first prints [9, 10, 100] as integers — no SORT_NATURAL needed, because they were never strings once PHP stored them. The second prints [street, city, country], imposing a domain order that no sort flag could express.

Example · php
<?php

// PHP casts integer-like string keys to integers.
$ports = collect(['10' => 'ten', '9' => 'nine', '100' => 'hundred']);

print_r($ports->sortKeys()->keys()->all());

// A comparator over the keys themselves.
$schema = collect(['country' => 'FR', 'street' => 'Rue X', 'city' => 'Paris']);

$order = ['street', 'city', 'country'];

print_r(
    $schema->sortKeysUsing(
        fn ($a, $b) => array_search($a, $order, true) <=> array_search($b, $order, true)
    )->keys()->all()
);

In an application: tidying a groupBy result

groupBy() builds its keys in the order rows arrive, so an alphabetical index needs an explicit sortKeys() even when the underlying query was ordered. The grouped collections that are the values are left untouched.

Example · php
<?php

namespace App\Http\Controllers;

use App\Models\Contact;

class DirectoryController extends Controller
{
    public function index()
    {
        $grouped = Contact::orderBy('name')
            ->get()
            ->groupBy(fn (Contact $c) => strtoupper($c->name[0]));

        // groupBy keeps first-encountered order; sortKeys makes it A-Z.
        return view('directory', ['letters' => $grouped->sortKeys()]);
    }
}

Discussion

  • Be the first to comment on this lesson.