Signature
strcmp(string $string1, string $string2): intPurpose
strcmp() compares two strings and tells you how they are ordered. It is binary safe, meaning it works on raw bytes. Embedded null bytes and non-text data do not stop the comparison. The comparison is case sensitive and ignores locale rules, so it is predictable but not suited to human-friendly alphabetical sorting.
Use it when you need an exact ordering or an exact equality test, for instance as a sort callback or a tie-breaker.
Signature
Parameters
$string1: the first string.$string2: the second string.
Neither parameter has a default, so both are required.
Return value
The function returns an int:
- a value less than 0 if
$string1sorts before$string2; - a value greater than 0 if
$string1sorts after$string2; - 0 if the strings are identical.
Only the sign of the result is meaningful. Since PHP 8.2 the function is no longer guaranteed to return the difference of the string lengths when the lengths differ. It may simply return -1 or 1. Never rely on the magnitude. If you want a stable value, normalise it with strcmp($a, $b) <=> 0.
Example 1: reading the sign
This example normalises each result to -1, 0 or 1. Notice that "Hello" sorts before "hello", because uppercase ASCII letters have lower byte values than lowercase ones.
$pairs = [["apple", "apple"], ["apple", "banana"], ["banana", "apple"], ["Hello", "hello"]];
$results = [];
foreach ($pairs as [$a, $b]) {
$results[] = strcmp($a, $b) <=> 0;
}
echo json_encode($results), "\n";[0,-1,1,-1]
Example 2: sorting with strcmp
Because strcmp() returns a negative, zero or positive integer, it can be passed by name to usort(). The result is a byte-order sort, so every capitalised word comes before every lowercase word.
$names = ["pear", "Apple", "banana", "apple", "Banana"];
usort($names, 'strcmp');
echo json_encode($names), "\n";["Apple","Banana","apple","banana","pear"]
Example 3: prefixes, empty strings and numeric strings
A shorter string that is a prefix of a longer one sorts first, and the empty string sorts before any non-empty string. Numeric-looking strings are compared as text, not as numbers. The last two entries show the difference between loose == and strcmp(). PHP treats "10" and "1e1" as equal numbers under ==, but they are different byte sequences.
$checks = [
"prefix" => strcmp("app", "apple") <=> 0,
"empty" => strcmp("", "a") <=> 0,
"numeric" => strcmp("10", "9") <=> 0,
"loose" => "10" == "1e1",
"strcmp" => strcmp("10", "1e1") === 0,
];
echo json_encode($checks), "\n";{"prefix":-1,"empty":-1,"numeric":-1,"loose":true,"strcmp":false}
Edge cases
- Case sensitivity.
strcmp("a", "A")is not zero. For a case-insensitive check, usestrcasecmp(). - No locale awareness. Accented or non-English text is compared by its bytes. For locale-based ordering, look at
strcoll()orCollator::compare(). - Multibyte text. UTF-8 strings are compared byte by byte. Identical strings still give
0, but the order of different characters follows their encoded bytes, not dictionary order. - Type errors. Both arguments must be strings. In the default coercive mode, scalar values such as integers are converted to strings. With
declare(strict_types=1)an integer argument raises aTypeError. Passing an array always raises aTypeError. - Partial comparison. If you only care about the first few characters,
strncmp()is a better fit. To compare from an offset, usesubstr_compare().
Common mistakes
- Treating the result like a boolean.
if (strcmp($a, $b))is true when the strings are different, because the function returns0for equal strings. This reads backwards and causes bugs. Preferstrcmp($a, $b) === 0, or simply$a === $bwhen you only need equality. - Comparing against a specific number. Code that checks for
-1or1, or that uses the value as a length difference, can break because only the sign is reliable. Compare with< 0,> 0or normalise with<=> 0. - Expecting natural or human sorting.
"10"sorts before"9"and uppercase sorts before lowercase. If you want numbers or natural order, a different function is needed. - Using it for secrets. An ordinary comparison is not designed for comparing passwords or tokens. Use the purpose-built functions for those tasks.
Related functions
strcasecmp()for case-insensitive full comparison.strncmp()for comparing only the first n bytes.substr_compare()for comparing from an offset.strcoll()andCollator::compare()for locale-aware ordering.similar_text()andlevenshtein()for measuring how similar strings are.
Recap
strcmp() compares two strings byte by byte, case sensitively and without locale rules. It returns a negative, zero or positive integer. Only the sign matters, and 0 means the strings are identical. It is useful as a sort callback and for exact ordering. Do not read its result as a boolean, and do not depend on the exact number returned.
Tested examples
$pairs = [["apple", "apple"], ["apple", "banana"], ["banana", "apple"], ["Hello", "hello"]];
$results = [];
foreach ($pairs as [$a, $b]) {
$results[] = strcmp($a, $b) <=> 0;
}
echo json_encode($results), "\n";
[0,-1,1,-1]
$names = ["pear", "Apple", "banana", "apple", "Banana"];
usort($names, 'strcmp');
echo json_encode($names), "\n";
["Apple","Banana","apple","banana","pear"]
$checks = [
"prefix" => strcmp("app", "apple") <=> 0,
"empty" => strcmp("", "a") <=> 0,
"numeric" => strcmp("10", "9") <=> 0,
"loose" => "10" == "1e1",
"strcmp" => strcmp("10", "1e1") === 0,
];
echo json_encode($checks), "\n";
{"prefix":-1,"empty":-1,"numeric":-1,"loose":true,"strcmp":false}