Signature
strnatcmp(string $string1, string $string2): intPurpose
strnatcmp() compares two strings using a "natural order" algorithm. Ordinary byte-by-byte comparison puts img10.png before img2.png, because the character 1 sorts before 2. A person reads the digit runs as whole numbers and expects img2.png to come first. strnatcmp() follows that human expectation: when it meets a run of digits in both strings, it compares the runs by numeric value instead of character by character.
It is most useful for file names, version-like labels, product codes and other identifiers that mix text and numbers.
Signature
Parameters
$string1: the first string to compare.$string2: the second string to compare.
Neither parameter has a default value, so both are required. The comparison is case sensitive. If you need case-insensitive natural ordering, use strnatcasecmp() instead.
Return value
The function returns an int:
- a value less than
0if$string1is less than$string2; - a value greater than
0if$string1is greater than$string2; 0if the two strings are considered equal.
Only the sign of the result has meaning. Since PHP 8.2 the function is no longer guaranteed to return the difference in string lengths when the lengths differ. It may simply return -1 or 1. Never rely on the magnitude, and never compare the result with a specific value such as -1 unless you first normalize it, for example with <=> 0.
Failure cases
The function does not return false and does not signal failure through its return value. Failures come from argument types:
- With
declare(strict_types=1), passing a non-string such as an integer throws aTypeError. - Without strict types, scalar values such as integers are converted to strings before comparison.
- Passing
nullto these non-nullable parameters is deprecated in modern PHP, so convert or validate values first.
Example 1: natural versus byte order
The helper below reduces the result to -1, 0 or 1, which makes the output independent of the exact magnitude returned.
function sign(int $n): int
{
return $n <=> 0;
}
echo json_encode([
sign(strnatcmp("img2.png", "img10.png")),
sign(strcmp("img2.png", "img10.png")),
sign(strnatcmp("img10.png", "img10.png")),
]), "\n";[-1,1,0]
The natural comparison says img2.png is smaller than img10.png. strcmp() disagrees, because it stops at the first differing character, 2 versus 1.
Example 2: sorting with a callback
Because strnatcmp() takes two strings and returns an integer, it works directly as a comparison callback for usort().
$names = ["img12.png", "img10.png", "img2.png", "img1.png"];
$natural = $names;
$plain = $names;
usort($natural, 'strnatcmp');
usort($plain, 'strcmp');
echo json_encode($natural), "\n";
echo json_encode($plain), "\n";["img1.png","img2.png","img10.png","img12.png"] ["img1.png","img10.png","img12.png","img2.png"]
Copying the array first lets you compare both orderings from the same input. If you only need to sort an array in place, natsort() does a similar job while preserving keys.
Example 3: case sensitivity
function sign(int $n): int
{
return $n <=> 0;
}
echo json_encode([
sign(strnatcmp("Alpha2", "alpha2")),
sign(strnatcasecmp("Alpha2", "alpha2")),
sign(strnatcmp("a10", "a9")),
]), "\n";[-1,0,1]
An uppercase A has a lower byte value than a lowercase a, so the case-sensitive call reports the first string as smaller. strnatcasecmp() ignores that difference and reports equality. The last value shows that a10 is greater than a9 once the digits are read as numbers.
Edge cases
- Only digit runs are numeric. Text portions are still compared character by character, so
file9andfolder1are decided by the letters before the digits. - Leading zeros and spaces. The algorithm has special handling for them. If your data contains values like
01or padded names, test those exact inputs rather than assuming a result. - Not a version comparer. Strings such as
1.10and1.9are treated as text with digit runs. For real version numbers, useversion_compare(). - Locale is not involved. The comparison works on bytes, so it does not apply language-specific collation rules, and it is not suited to accented or multibyte text ordering.
- Empty strings. An empty string is smaller than a non-empty one, and two empty strings are equal.
Common mistakes
- Testing for exactly
-1or1. Only the sign is meaningful. Use< 0,> 0or=== 0. - Forgetting case sensitivity.
Img2andimg2are not equal; switch tostrnatcasecmp()when appropriate. - Using
==on strings to compare numbers. Natural comparison is for ordering strings, not for deciding numeric equality. - Expecting stable locale-aware sorting. Use dedicated collation tools when human-language ordering matters.
- Passing mixed types under strict typing. Cast or validate values before calling.
Related functions
strnatcasecmp(): natural order, ignoring case.strcmp(): binary-safe comparison without natural number handling.strcasecmp(): binary-safe, case-insensitive comparison.natsort()andnatcasesort(): sort whole arrays using natural order.version_compare(): compare version strings.
Recap
strnatcmp() orders strings the way people read embedded numbers, so img2 comes before img10. It is case sensitive, returns an integer whose sign is the only reliable information, and fits naturally into usort(). Normalize the result with <=> 0 when you need predictable values, and choose a related function when you need case-insensitivity or true version comparison.
Tested examples
function sign(int $n): int
{
return $n <=> 0;
}
echo json_encode([
sign(strnatcmp("img2.png", "img10.png")),
sign(strcmp("img2.png", "img10.png")),
sign(strnatcmp("img10.png", "img10.png")),
]), "\n";[-1,1,0]
$names = ["img12.png", "img10.png", "img2.png", "img1.png"];
$natural = $names;
$plain = $names;
usort($natural, 'strnatcmp');
usort($plain, 'strcmp');
echo json_encode($natural), "\n";
echo json_encode($plain), "\n";["img1.png","img2.png","img10.png","img12.png"] ["img1.png","img10.png","img12.png","img2.png"]
function sign(int $n): int
{
return $n <=> 0;
}
echo json_encode([
sign(strnatcmp("Alpha2", "alpha2")),
sign(strnatcasecmp("Alpha2", "alpha2")),
sign(strnatcmp("a10", "a9")),
]), "\n";[-1,0,1]