strncmp
Compares the first n bytes of two strings, case sensitively and binary safely.
strncmp(string $string1, string $string2, int $length): int- Added in PHP 4.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$string1 | string | The first string. |
$string2 | string | The second string. |
$length | int | Number of characters to use in the comparison. |
Return value
intA value less than 0 if string1 is less than string2, a value greater than 0 if string1 is greater than string2, and 0 if they are equal.
Errors
Throws a ValueError if length is negative.
Changelog
- PHP 8.2.0This function is no longer guaranteed to return strlen($string1) - strlen($string2) when string lengths are not equal, but may now return -1 or 1 instead.
strncmp() compares at most the first n bytes of two strings. It is strcmp() with a hard limit, and it is binary safe — null bytes and arbitrary binary data are compared like any other byte.
When to reach for it
Use it for prefix tests and for cheap ordering of long strings where only the head matters. Checking that a resolved path stays inside a base directory, filtering records by a country or type prefix, or peeking at a file's magic bytes are all a good fit, because the comparison stops after n bytes instead of scanning megabytes.
Since PHP 8.0, str_starts_with() expresses a plain prefix test more clearly and needs no length argument. Prefer it unless you need the three-way ordering result, a case-insensitive test (strncasecmp()), or a comparison that starts somewhere other than position 0 (substr_compare()).
What trips people up
The length is in bytes. Hard-coding it invites drift, so write strlen($prefix). The length is also not clamped to the shorter string: comparing three bytes of 'ab' against 'abc' is non-zero, not zero.
Only the sign of the return value is meaningful. Since PHP 8.2 it is typically -1, 0 or 1, so never do arithmetic on it.
Example
When to use it
- Confirm a resolved file path still begins with an allowed base directory.
- Filter records whose reference starts with a given country or type code.
- Detect a file format from its leading magic bytes without reading the whole file.
Frequently asked questions
What is the difference between strcmp and strncmp?
strcmp compares the whole of both strings; strncmp stops after the number of bytes you pass as the third argument. Use strncmp when only the beginning matters.
Should I use strncmp or str_starts_with?
Use str_starts_with for a plain prefix test — it is clearer and needs no length. Use strncmp when you need the three-way less/equal/greater result for sorting.
Can I use strncmp to compare API tokens?
No. strncmp returns as soon as bytes differ, which leaks timing information. Use hash_equals() for any secret comparison.
More examples
strncmp versus str_starts_with
The first two lines are equivalent, which is why str_starts_with is the clearer choice for a plain prefix test. The third shows that strncmp is case sensitive; strncasecmp would return 0 there.
<?php
$s = 'php8.5-cli';
var_dump(strncmp($s, 'php', 3) === 0); // bool(true)
var_dump(str_starts_with($s, 'php')); // bool(true)
var_dump(strncmp($s, 'PHP', 3) === 0); // bool(false) — case sensitive
echo str_starts_with($s, 'php') ? "starts with php\n" : "no\n";Filtering by prefix
Only GB-1001 and GB-0003 survive the filter, and array_values reindexes the result so it is a clean list again. array_filter alone would have kept the original keys 0 and 2.
<?php
$rows = ['GB-1001', 'US-2002', 'GB-0003', 'DE-4004'];
$gb = array_values(array_filter(
$rows,
static fn (string $r): bool => strncmp($r, 'GB-', 3) === 0
));
print_r($gb);
echo count($gb), " GB rows\n";
Discussion