====== PHP RFC: SORT_STRICT Flag ======
* Version: 0.1
* Date: 2025-11-29
* Author: Jason Marble, jmarble@intuitivetechnology.com
* Status: Draft
* Implementation: https://github.com/php/php-src/pull/20683
===== 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:
$values = ["1", true, 1, null, 1.0];
sort($values, SORT_STRICT);
var_dump($values);
// Sorted by type hierarchy: NULL < Bool < Int < Float < String
// array(5) {
// [0]=> NULL
// [1]=> bool(true)
// [2]=> int(1)
// [3]=> float(1.0)
// [4]=> string(1) "1"
// }
=== 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:
* Yes
* No
===== Patches and Tests =====
WIP
===== Implementation =====
TODO: After acceptance.
===== References =====
* [[https://github.com/php/php-src/pull/7806|PR #7806: Add SORT_STRICT option to array_unique() (C. Scott Ananian)]] (2022)
* [[https://github.com/php/php-src/issues/10526|Issue #10526: array_unique: add way to compare items with an identity check]] (2023)
* [[https://github.com/php/php-src/pull/10567|PR #10567: Implement SORT_STRICT flag (Niels Dossche)]] (2023)
* [[https://github.com/php/php-src/issues/20262|Issue #20262: array_unique() with SORT_REGULAR returns duplicate values]] (2025)
===== Rejected Features =====
None yet.
===== Changelog =====
* 2025-11-29: Initial draft