PHP RFC: SORT_STRICT Flag
- Version: 0.1
- Date: 2025-11-29
- Author: Jason Marble, [email protected]
- Status: Draft
Introduction
This RFC proposes SORT_STRICT, a new flag that enables deterministic, type-aware sorting without sacrificing PHP's flexibility with mixed-type arrays.
PHP was famously created as a loosely typed language, prioritizing flexibility and ease of use. However, the introduction of strict types in PHP 7 marked a massive paradigm shift for the language. Over the last decade, the ecosystem has matured significantly; major frameworks like Symfony and Laravel, along with modern coding standards like PER, have effectively pushed strict typing from an optional feature to a de facto standard for professional PHP development.
Despite this evolution, there is no native way to sort or filter arrays without type coercion. The sort() family defaults to SORT_REGULAR (loose equality), while array_unique() defaults to SORT_STRING (string casting), neither of which distinguishes between values of different types. This creates a friction point where modern application logic is strict, but utility functions remain loose. Currently, developers wishing to filter unique values strictly or sort mixed-type arrays deterministically must implement userspace closures using usort or specific loops. This is verbose, slower than internal C implementations, and prone to error.
Proposal
Add a new constant SORT_STRICT that can be passed to the following functions:
- Value Sorting:
sort(),rsort() - Associative Value Sorting:
asort(),arsort() - Key Sorting:
ksort(),krsort() - Multi-Array Sorting:
array_multisort() - Uniqueness:
array_unique()
Comparison Logic: The "Strict Total Order"
SORT_STRICT implements a two-step comparison:
Step 1: Compare Types
Values are first compared by their type according to this hierarchy:
NULL < Bool < Int < Float < String < Array < Object < Resource
This ordering progresses from simple to complex types, aligning with PHP's internal type representation.
If types differ, the comparison is decided here. No type coercion occurs.
Step 2: Compare Values
If types are identical, standard PHP comparison semantics apply:
| Type | Comparison Method |
|---|---|
| NULL | Always equal |
| Bool | false < true |
| Int | Numeric comparison |
| Float | Numeric comparison |
| String | Binary comparison (strcmp) |
| Array | Standard array comparison, with SORT_STRICT applied recursively to elements |
| Object | Standard object comparison, with SORT_STRICT applied recursively to properties of same-class objects (enums are compared by identity) |
| Resource | Resource ID comparison |
Differences from SORT_REGULAR
SORT_STRICT applies no type coercion at any level:
- Different types are ordered by type, never compared by value.
- Same-type values are compared directly, without coercion (e.g., strings lexicographically, not numerically).
The following table illustrates common scenarios where SORT_STRICT provides deterministic results versus SORT_REGULAR:
| Input Array | SORT_REGULAR Result | SORT_STRICT Result | Reason |
|---|---|---|---|
[1, “1”] | Equal (treats as duplicates) | Distinct (Int vs String) | Different types are not equal |
[“10”, “2”] | [“2”, “10”] (Numeric) | [“10”, “2”] (Lexicographic) | Strings are not cast to ints |
[“1e3”, “1000”] | Equal (treats as duplicates) | [“1000”, “1e3”] (Lexicographic) | No numeric string coercion |
[null, false] | Equal (treats as duplicates) | Distinct (Null vs Bool) | Different types are not equal |
Examples
array_unique(): Preserving Type-Distinct Values
Prevent data loss when filtering arrays containing distinct values that loose comparison treats as duplicates:
$values = [0, "0", null, false, ""]; var_dump(array_unique($values, SORT_REGULAR)); // 3 values lost to type coercion // array(2) { // [0]=> int(0) // [4]=> string(0) "" // } var_dump(array_unique($values, SORT_STRICT)); // All 5 values preserved // array(5) { // [0]=> int(0) // [1]=> string(1) "0" // [2]=> NULL // [3]=> bool(false) // [4]=> string(0) "" // }
sort(): Type-Aware Ordering
Sort mixed-type arrays with deterministic, type-based ordering:
sort(): Order-Independent Value Matching
Compare arrays for identical values regardless of order:
$expected = [1, "1", true]; $actual = [true, 1, "1"]; sort($expected, SORT_REGULAR); sort($actual, SORT_REGULAR); var_dump($expected === $actual); // bool(false) - result depends on input order sort($expected, SORT_STRICT); sort($actual, SORT_STRICT); var_dump($expected === $actual); // bool(true) - consistent type-based ordering
Backward Incompatible Changes
None. This RFC adds a new constant and does not modify existing behavior.
Proposed PHP Version(s)
Next PHP 8.x
RFC Impact
To the Ecosystem
IDEs, static analyzers, and language servers will need to recognize the new SORT_STRICT constant. No breaking changes are expected.
To Existing Extensions
None.
To SAPIs
None.
Open Issues
None currently.
Future Scope
The array_diff() and array_intersect() families currently hardcode string comparison (SORT_STRING) with no way to change the comparison mode. A future RFC could add a flags parameter to these functions, exposing all sort flags including SORT_STRICT:
array_diff(array $array, array ...$arrays, int $flags = SORT_STRING)array_intersect(array $array, array ...$arrays, int $flags = SORT_STRING)
This would enable:
// Current behavior (string comparison) array_diff([1, 2], ["1", "3"]); // [2] - int 1 matches string "1" // With SORT_STRICT array_diff([1, 2], ["1", "3"], SORT_STRICT); // [1, 2] - no matches, different types // With SORT_NUMERIC array_diff(["10", "2"], [2, 10], SORT_NUMERIC); // [] - all match numerically
Voting Choices
Primary vote requiring a 2/3 majority:
Patches and Tests
WIP
Implementation
TODO: After acceptance.
References
Rejected Features
None yet.
Changelog
- 2025-11-29: Initial draft