str_contains
Checks whether a string contains a given substring, case-sensitively.
str_contains(string $haystack, string $needle): bool- Added in PHP 8.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$haystack | string | The string to search in. |
$needle | string | The substring to search for. |
Return value
booltrue if needle occurs anywhere in haystack, false otherwise.
Errors
Throws a TypeError if a non-string is passed under strict_types; otherwise no errors are raised.
str_contains answers the one question people actually ask of strpos: is this text in there? It returns a plain boolean, so it reads naturally in a condition and removes an entire class of bugs.
When to reach for it
Use it any time you only need presence, not position: checking a Content-Type header for json, filtering a list of filenames, testing whether a message body mentions a keyword, or short-circuiting before a more expensive parse. If you need to know where the match is, or want to slice around it, strpos and strstr are still the right tools.
What trips people up
It is byte-based and case-sensitive. str_contains('Hello', 'hello') is false; lowercase both sides, or use stripos($h, $n) !== false, for a case-insensitive check. An empty needle always returns true, because every string contains the empty string — guard against empty user input before searching or a blank search box will match everything. Being byte-based, it is safe for UTF-8 substring checks (a valid UTF-8 needle can only match at a character boundary), but it knows nothing about Unicode case folding or accent normalisation.
Example
When to use it
- Filter a list of filenames down to those containing a keyword
- Check a Content-Type header for "json" before decoding a body
- Detect a banned word in user-submitted text
- Skip log lines that do not mention a given request ID
Frequently asked questions
What is the difference between str_contains and strpos?
str_contains returns a boolean, strpos returns the byte offset of the match or false. Use str_contains when you only care whether the substring is present; the strpos form needs an explicit !== false comparison because offset 0 is falsy.
Is str_contains case-sensitive?
Yes. Lowercase both strings first, or use stripos($haystack, $needle) !== false, for a case-insensitive check.
Does str_contains work with UTF-8 strings?
Yes for substring checks. It compares bytes, and a valid UTF-8 needle can only match on a character boundary, so results are correct. It does not handle Unicode case folding or accent normalisation.
More examples
Case-insensitive containment
The first check is false because str_contains compares bytes exactly. Lowercasing both operands, or falling back to stripos, both report true. The stripos form avoids allocating two lowercased copies, which matters inside a loop over many rows.
<?php
$subject = 'Order CANCELLED by customer';
$needle = 'cancelled';
var_dump(str_contains($subject, $needle));
var_dump(str_contains(strtolower($subject), strtolower($needle)));
var_dump(stripos($subject, $needle) !== false);Guarding an empty search term
The guarded search returns nothing for an empty term, while the unguarded filter on the last line returns every row — that is the empty-needle rule biting. It is the reason a blank search box can appear to match the whole table.
<?php
$rows = ['alpha', 'beta', 'gamma'];
function search(array $rows, string $term): array {
if ($term === '') {
return [];
}
return array_values(array_filter($rows, fn ($r) => str_contains($r, $term)));
}
print_r(search($rows, 'a'));
print_r(search($rows, ''));
print_r(array_filter($rows, fn ($r) => str_contains($r, '')));
Discussion