I ran a few tests on 2d arrays and found that in some contexts, native sorting functions can give unexpected results when array keys are 2, 5, 10, or 13.
$expected = range(0, 11);
$array = array_fill(0, 50, $expected); // create a 2d array with 50 rows containing 12 integer values
array_walk($array, 'sort'); // sort the 12 integer values within each row
var_export(
array_filter(
$array,
fn($row) => $row !== $expected // only keep rows which are sorted incorrectly
)
);
- ❌
sort()
second level int values test - ❌
sort()
second level float values test - ❌
sort()
second level numeric string values test - ✅
sort()
second level non-numeric string values test - ❌
krsort()
second level numeric string values test - ❌
krsort()
second level int values test - ✅
krsort()
second level non-numeric string values test
❌ Sorting rows of alphanumeric strings causes too many unintended sorting outcomes to list.
What is causing these inconsistencies?
I ran a few tests on 2d arrays and found that in some contexts, native sorting functions can give unexpected results when array keys are 2, 5, 10, or 13.
$expected = range(0, 11);
$array = array_fill(0, 50, $expected); // create a 2d array with 50 rows containing 12 integer values
array_walk($array, 'sort'); // sort the 12 integer values within each row
var_export(
array_filter(
$array,
fn($row) => $row !== $expected // only keep rows which are sorted incorrectly
)
);
- ❌
sort()
second level int values test - ❌
sort()
second level float values test - ❌
sort()
second level numeric string values test - ✅
sort()
second level non-numeric string values test - ❌
krsort()
second level numeric string values test - ❌
krsort()
second level int values test - ✅
krsort()
second level non-numeric string values test
❌ Sorting rows of alphanumeric strings causes too many unintended sorting outcomes to list.
What is causing these inconsistencies?
Share Improve this question edited Feb 2 at 13:36 mickmackusa asked Feb 2 at 13:17 mickmackusamickmackusa 48.1k13 gold badges93 silver badges161 bronze badges Recognized by PHP Collective1 Answer
Reset to default 4The seldom realized issue arises because array_walk($array, 'sort');
or array_walk($array, sort(...));
calls sort()
with an unintended second argument.
When array_walk()
is implemented in this way, it passes two arguments to the callback function -- $value
by reference as well as the $key
.
The second argument of sort()
is meant to be for a consistent sorting flag, not ever-changing array keys.
Numeric keys of 2, 5, 10, and 13 correspond to sorting flag constants which call for comparing values as strings instead of numeric values.
The fundamental sorting constants list:
Constant | Integer Value | Description |
---|---|---|
SORT_REGULAR | 0 | Standard comparison |
SORT_NUMERIC | 1 | Numeric comparison |
SORT_STRING | 2 | String comparison |
SORT_LOCALE_STRING | 5 | String comparison based on locale settings |
SORT_NATURAL | 6 | Natural order string comparison |
SORT_FLAG_CASE | 8 | Case-insensitive sorting (used with SORT_STRING or SORT_NATURAL) |
Relevant combined flags:
Constant | Integer Value |
---|---|
SORT_STRING | SORT_FLAG_CASE | 10 (2 + 8) |
SORT_LOCALE_STRING | SORT_NATURAL | 13 (5 + 6) |
Even if some Stack Overflow posts work properly in their context, it would be better practice to not allow your codebase to use these potential silent-bug producers.