In PHP, how do the SORT_STRING, SORT_NATURAL and SORT_FLAG_CASE flags change the order that sort() produces for strings?
answer
- default is SORT_REGULAR
- numeric strings compare as numbers by default
- SORT_STRING: byte order, '10' before '2'
- SORT_NATURAL: img2 before img10
- SORT_FLAG_CASE combines with bitwise OR
basics
~10 sSORT_STRING compares values as strings byte by byte, so '10' sorts before '2'; SORT_NATURAL orders digit runs by number, so 'img2' precedes 'img10'; SORT_FLAG_CASE, OR-ed with either, ignores ASCII letter case.
solid answer
~40 sThe flag is the optional second argument of `sort()`, `rsort()`, `asort()`, `arsort()`, `ksort()` and `krsort()`, and the default is `SORT_REGULAR`, which uses PHP's normal comparison: two numeric strings such as `'10'` and `'9'` compare as numbers. `SORT_STRING` compares everything as strings byte by byte, so `'10'` comes before `'9'` and every uppercase ASCII letter sorts before every lowercase one. `SORT_NATURAL` compares runs of digits as numbers inside a string, so `img2.png` lands before `img10.png`. `SORT_FLAG_CASE` is a modifier you combine with `|` and only with `SORT_STRING` or `SORT_NATURAL`; since PHP 8.2 it folds ASCII case only, whatever the locale. `SORT_NUMERIC` and `SORT_LOCALE_STRING` complete the set.
code
php · 18 lines<?php
declare(strict_types=1);
$files = ['img12.png', 'IMG3.png', 'img10.png', 'img2.png'];
$a = $files; sort($a, SORT_STRING);
// IMG3.png, img10.png, img12.png, img2.png
$b = $files; sort($b, SORT_NATURAL);
// IMG3.png, img2.png, img10.png, img12.png
$c = $files; sort($c, SORT_NATURAL | SORT_FLAG_CASE);
// img2.png, IMG3.png, img10.png, img12.png
$n = ['10', '9', '2', '1'];
sort($n); // '1', '2', '9', '10' (numeric strings)
sort($n, SORT_STRING); // '1', '10', '2', '9'
echo implode(' ', $c), PHP_EOL;go deeper
Recall that the default is SORT_REGULAR, that SORT_STRING gives byte order and SORT_NATURAL gives human order for embedded numbers.
Explain why numeric strings sort numerically by default, how SORT_FLAG_CASE combines with | and only with SORT_STRING or SORT_NATURAL, and what natsort and natcasesort add.
Choose flags deliberately for ids, user-facing names and numeric CSV data, and know that case folding is ASCII only since 8.2, so non-ASCII names need locale or intl collation.
Decide where collation belongs: a byte-order SORT_STRING for machine keys, and one shared, locale-aware ordering for anything shown to users, so lists sort the same across pages.
## Where the flag goes The six flag-based sort functions (`sort`, `rsort`, `asort`, `arsort`, `ksort`, `krsort`) take an optional second argument, `int $flags = SORT_REGULAR`. The function name decides *what* is ordered and whether keys survive; the flag decides *how two elements are compared*. The same constants are accepted by `array_multisort()` per array, and `array_unique()` takes them too (its default is `SORT_STRING`). ## The comparison modes | Flag | How two elements are compared | `['10', '9', '2', '1']` sorts to | |---|---|---| | `SORT_REGULAR` (default) | PHP's normal comparison: numeric strings as numbers, other strings as strings | `'1', '2', '9', '10'` | | `SORT_NUMERIC` | both converted to numbers | `'1', '2', '9', '10'` | | `SORT_STRING` | both converted to strings, compared byte by byte | `'1', '10', '2', '9'` | | `SORT_LOCALE_STRING` | as strings, using the current locale's collation | depends on `setlocale()` | | `SORT_NATURAL` | as strings, but runs of digits compared as numbers | `'1', '2', '9', '10'` | The interesting differences appear with strings that mix letters and digits, or letters of different case. ## A file list, four ways Take `['img12.png', 'IMG3.png', 'img10.png', 'img2.png']`: 1. **`SORT_REGULAR`** and **`SORT_STRING`** both give `IMG3.png, img10.png, img12.png, img2.png`. None of these strings is numeric, so the default also compares them as strings. Byte order puts `I` (0x49) before `i` (0x69), and `'1'` before `'2'`, so `img10` precedes `img2`. 2. **`SORT_NATURAL`** gives `IMG3.png, img2.png, img10.png, img12.png`. Digit runs now compare as numbers, so 2 < 10 < 12, but case still matters and `IMG3` stays first. 3. **`SORT_NATURAL | SORT_FLAG_CASE`** gives `img2.png, IMG3.png, img10.png, img12.png`: natural order with letter case ignored. This is what people usually mean by "sort file names". 4. **`SORT_STRING | SORT_FLAG_CASE`** gives `img10.png, img12.png, img2.png, IMG3.png`: case ignored, but still byte order on the digits. `natsort()` and `natcasesort()` are the key-preserving shortcuts for the last two ideas; they behave like `asort()` with `SORT_NATURAL` and `SORT_NATURAL | SORT_FLAG_CASE`. ## How SORT_FLAG_CASE combines `SORT_FLAG_CASE` is a bit you add with the bitwise OR operator. Internally PHP masks it off to find the base mode and then checks the bit only when that base mode is `SORT_STRING` or `SORT_NATURAL`. With `SORT_REGULAR` or `SORT_NUMERIC` it is silently ignored: - `sort($names, SORT_STRING | SORT_FLAG_CASE)` compares case-insensitively. - `sort($names, SORT_FLAG_CASE)` is the same as `SORT_REGULAR`, because the flag's base mode is 0. Since PHP 8.2, case folding for these flags is **ASCII only**, as if the locale were `"C"`. Letters outside ASCII are not folded, so `É` and `é` still compare by their bytes. For language-aware ordering, `SORT_LOCALE_STRING` after `setlocale()` or a collator from the intl extension is the tool. ## Mistakes that show up in review 1. **Passing `SORT_FLAG_CASE` alone** and expecting case-insensitive order; it needs `SORT_STRING` or `SORT_NATURAL` beside it. 2. **Sorting scores stored as strings with `SORT_STRING`**, which puts `'100'` before `'95'` because `'1'` is smaller than `'9'`. 3. **Expecting `sort()` to give human order for file names.** The default compares non-numeric strings byte by byte, so `img10` lands before `img2` until you ask for `SORT_NATURAL`. ## Choosing a flag - **Codes, ids and hashes** that must sort the same everywhere: `SORT_STRING`. It is deterministic and does not depend on locale or numeric-looking values. - **Human-facing names with numbers in them** (files, versions like `v2` and `v10`, chapter titles): `SORT_NATURAL | SORT_FLAG_CASE`. - **Numbers stored as strings**, such as scores read from a CSV: `SORT_NUMERIC`, or cast to `int` first. - **Mixed types in one array**: avoid `SORT_REGULAR`; the manual warns that sorting mixed values with it can give unexpected results, because each pair is compared by the ordinary comparison rules. Pick an explicit flag instead. The flag applies to keys in exactly the same way when you call `ksort()` or `krsort()`, which is how you get `p2` before `p10` in a map keyed by player id: `ksort($players, SORT_NATURAL)`.
- Why does sort() put '9' before '10' by default but after it with SORT_STRING?The default `SORT_REGULAR` uses PHP's ordinary comparison, and two numeric strings compare as numbers, so 9 < 10. `SORT_STRING` converts both to strings and compares bytes: the first byte `'1'` is smaller than `'9'`, so `'10'` comes first.
- How would you sort a map keyed by ids like p2 and p10 so that p2 comes first?Call `ksort($map, SORT_NATURAL)`. The flag applies to keys the same way it applies to values, digit runs compare as numbers, and `ksort()` keeps every value attached to its key. Add `| SORT_FLAG_CASE` if ids can differ in letter case.
saying these in an interview costs you the question
- SORT_FLAG_CASE on its own makes sort() case-insensitive
- The default sort flag compares numeric strings as strings
- SORT_NATURAL ignores letter case by default
- SORT_FLAG_CASE folds accented letters in the current locale
- SORT_NUMERIC orders 'img2.png' before 'img10.png'