Signature
strncmp(string $string1, string $string2, int $length): intPurpose
strncmp() performs a binary-safe, case-sensitive comparison of at most the first $length characters of two strings. It works like strcmp(), but you set an upper limit on how much of each string is examined. The usual uses are prefix checks (does this line start with ERROR:?) and ordering strings by a fixed-width key.
Signature
Parameters
$string1: the first string.$string2: the second string.$length: the maximum number of characters to compare from each string. There is no default, so you must always pass it.
The comparison is byte-based, so "character" here means a single byte. That is fine for ASCII. With multibyte text such as UTF-8, a limit can cut through the middle of a character.
Return value and failure cases
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 compared portions are equal.
Only the sign of the result is meaningful. Since PHP 8.2 the function is no longer guaranteed to return the difference in string lengths when the lengths differ. It may return -1 or 1 instead. Test with === 0, < 0 or > 0, or normalise with <=> 0, and never rely on the exact magnitude.
A negative $length is not allowed in PHP 8. It throws a ValueError. A $length of 0 compares nothing, so the result is 0.
Example 1: filtering lines by prefix
The most common use is checking whether a string begins with a known marker. Compare the same number of bytes as the marker has, and test for 0.
$lines = ['ERROR: disk full', 'INFO: started', 'ERROR: timeout'];
$errors = [];
foreach ($lines as $line) {
if (strncmp($line, 'ERROR:', 6) === 0) {
$errors[] = $line;
}
}
echo json_encode($errors, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);["ERROR: disk full","ERROR: timeout"]
The marker ERROR: is six bytes long, so 6 is the right limit. Writing the number by hand is easy to get wrong. If the marker changes, update the number too, or compute it with strlen().
Example 2: reading the sign
The $length limit decides which part of each string takes part in the comparison. Differences after that point are ignored.
$results = [
'equal_prefix' => strncmp('apple', 'apricot', 2) <=> 0,
'less' => strncmp('apple', 'apricot', 3) <=> 0,
'greater' => strncmp('banana', 'apple', 1) <=> 0,
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);{"equal_prefix":0,"less":-1,"greater":1}With a limit of 2 both strings begin with ap, so they are equal. With a limit of 3 the third bytes are p and r, so the first string is smaller. The <=> 0 turns any negative or positive result into -1 or 1, which keeps the output predictable.
Example 3: edge cases
echo json_encode([
'case' => strncmp('Hello', 'hello', 5) <=> 0,
'short' => strncmp('abc', 'abcdef', 10) <=> 0,
'limited' => strncmp('abc', 'abcdef', 3),
'zero' => strncmp('x', 'y', 0),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
try {
strncmp('a', 'a', -1);
} catch (ValueError $e) {
echo get_class($e), "\n";
}{"case":-1,"short":-1,"limited":0,"zero":0}
ValueError
The uppercase H sorts before lowercase h in byte order, so the case-sensitive comparison is negative. When $length is larger than a string, the comparison stops at the end of the shorter one. If one string is a proper prefix of the other, the shorter one is considered smaller, which is why short is -1. Limiting the comparison to 3 bytes makes abc and abcdef equal. A length of 0 always gives 0, and a negative length throws ValueError.
Edge cases to remember
- Case sensitivity:
strncmp('Hello', 'hello', 5)is not0. Usestrncasecmp()for ASCII case-insensitive comparison. - Short strings: if either string has fewer than
$lengthbytes, the comparison covers the shorter string, and a length difference counts as a difference. - Empty strings: two empty strings are equal for any non-negative length.
- Binary data: null bytes are compared like any other byte, so the function is binary safe.
Common mistakes
- Using the result as a boolean.
if (strncmp($a, $b, 3))is true when the strings differ, which is the opposite of what many people expect. Compare explicitly with=== 0. - Assuming the return value is a difference. Only the sign is meaningful, and PHP 8.2 changed the possible magnitudes.
- Using a wrong length. A limit shorter than the marker accepts false matches, and a longer one can reject valid strings.
- Expecting case-insensitive matching. The comparison is exact byte by byte.
- Passing a negative length. Validate any length that comes from variable data before calling the function.
Related functions
strcmp()compares whole strings in a binary-safe way.strncasecmp()is the case-insensitive version of this function.substr_compare()compares from an offset, up to a given length.substr()extracts part of a string, which you can then compare yourself.strstr()finds the first occurrence of a string.preg_match()handles pattern-based checks.
Recap
strncmp() compares only the first $length bytes of two strings, case-sensitively. A result of 0 means the compared portions match. Treat any other value only as negative or positive, never as an exact distance, and remember that a negative length throws a ValueError.
Tested examples
$lines = ['ERROR: disk full', 'INFO: started', 'ERROR: timeout'];
$errors = [];
foreach ($lines as $line) {
if (strncmp($line, 'ERROR:', 6) === 0) {
$errors[] = $line;
}
}
echo json_encode($errors, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
["ERROR: disk full","ERROR: timeout"]
$results = [
'equal_prefix' => strncmp('apple', 'apricot', 2) <=> 0,
'less' => strncmp('apple', 'apricot', 3) <=> 0,
'greater' => strncmp('banana', 'apple', 1) <=> 0,
];
echo json_encode($results, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
{"equal_prefix":0,"less":-1,"greater":1}
echo json_encode([
'case' => strncmp('Hello', 'hello', 5) <=> 0,
'short' => strncmp('abc', 'abcdef', 10) <=> 0,
'limited' => strncmp('abc', 'abcdef', 3),
'zero' => strncmp('x', 'y', 0),
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
try {
strncmp('a', 'a', -1);
} catch (ValueError $e) {
echo get_class($e), "\n";
}
{"case":-1,"short":-1,"limited":0,"zero":0}
ValueError