Signature
strnatcasecmp(string $string1, string $string2): intPurpose
strnatcasecmp() compares two strings the way a person would read them, ignoring letter case. The "natural order" part matters when strings contain digits. A plain comparison goes character by character, so "file10" sorts before "file9" because 1 comes before 9. A natural comparison reads each run of digits as one number, so "file9" comes before "file10".
The function is the case-insensitive sibling of strnatcmp(). Use it for file names, version-like labels, product codes, or any list where people expect item2 to come before item10 whatever the capitalization.
Signature
Parameters and defaults
$string1: the first string to compare.$string2: the second string to compare.
Both parameters are required and there are no optional parameters. In a file without strict types, scalar values such as integers are converted to strings. Passing an array or other non-stringable value throws a TypeError.
Return value and failure cases
The function returns an int:
- a value less than
0when$string1sorts before$string2; - a value greater than
0when$string1sorts after$string2; 0when the strings are equal for this comparison.
Only the sign is meaningful. The manual notes that since PHP 8.2.0 the function is no longer guaranteed to return the length difference for strings of unequal length, and may return -1 or 1 instead. Compare the result with < 0, > 0 or === 0 rather than relying on a particular number.
There is no false return and no warning for ordinary strings. The only failure case is a type error for unsuitable arguments.
Example 1: reading the result
This is the basic behavior. Differences in case do not matter, so apple and Apple are equal.
var_dump(strnatcasecmp('Apple', 'Banana'));
var_dump(strnatcasecmp('Banana', 'Apple'));
var_dump(strnatcasecmp('apple', 'Apple'));int(-1) int(1) int(0)
Example 2: natural order versus plain order
Here strcasecmp() stops at 1 versus 9, while strnatcasecmp() sees the numbers 10 and 9. The code reduces each result to its sign with <=> 0 so the output does not depend on the exact number returned.
$a = 'File10.txt';
$b = 'file9.txt';
$result = [
'natural' => strnatcasecmp($a, $b) <=> 0,
'plain' => strcasecmp($a, $b) <=> 0,
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"natural":1,"plain":-1}Example 3: sorting with usort()
Because the function takes two strings and returns a signed integer, it works directly as a usort() callback. The mixed capitalization below does not disturb the order.
$files = ['Img12.png', 'img10.png', 'IMG2.png', 'img1.png'];
usort($files, 'strnatcasecmp');
echo json_encode($files, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);["img1.png","IMG2.png","img10.png","Img12.png"]
Edge cases
- Empty strings. An empty string sorts before any non-empty string.
- Digits only at one position. Natural comparison only changes how runs of digits are treated. Text parts are still compared character by character, ignoring case.
- Dotted numbers. A value such as
1.10is not treated as a decimal number or a semantic version. The digit runs are compared separately. For real version numbers,version_compare()is the better tool. - Leading zeros and spaces. These can influence natural ordering in ways that are easy to overlook. If your data may contain them, test those cases or normalize the strings first.
- Non-ASCII text. The function works on bytes and is not a multibyte-aware collation. Do not use it for language-specific alphabetical ordering of accented or non-Latin text.
Common mistakes
- Checking for
-1or1only. The sign is the contract. Writestrnatcasecmp($a, $b) < 0instead of comparing with a fixed number. - Treating the result as a boolean.
0means the strings are equal, and0is falsy. Usingif (strnatcasecmp($a, $b))actually tests for inequality. - Using plain comparison for numbered names.
strcasecmp()andsort()with default flags giveitem10beforeitem2in many lists. - Expecting numeric equality.
"a1"and"a01"are different strings. Do not assume natural order makes them interchangeable. - Using it for equality checks on secrets. It is an ordering helper, not a safe comparison for tokens or passwords.
Related functions
strnatcmp(): the same natural-order comparison, but case-sensitive.strcasecmp(): binary-safe case-insensitive comparison without natural number handling.strcmp(): binary-safe, case-sensitive comparison.strncasecmp()andstrncmp(): compare only the first n characters.natcasesort(): sorts an array in place using the same idea.version_compare(): compares version strings.
Recap
strnatcasecmp() takes two strings and returns a negative number, zero, or a positive number according to a human-friendly, case-insensitive order. Treat only the sign as meaningful, remember that 0 means equal, and reach for it as a usort() callback when digits inside strings should count as numbers.
Tested examples
var_dump(strnatcasecmp('Apple', 'Banana'));
var_dump(strnatcasecmp('Banana', 'Apple'));
var_dump(strnatcasecmp('apple', 'Apple'));int(-1) int(1) int(0)
$a = 'File10.txt';
$b = 'file9.txt';
$result = [
'natural' => strnatcasecmp($a, $b) <=> 0,
'plain' => strcasecmp($a, $b) <=> 0,
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"natural":1,"plain":-1}
$files = ['Img12.png', 'img10.png', 'IMG2.png', 'img1.png'];
usort($files, 'strnatcasecmp');
echo json_encode($files, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);["img1.png","IMG2.png","img10.png","Img12.png"]