PHP字符串包含判断:从strpos到str_contains的全面指南304
在PHP编程中,判断一个字符串是否包含另一个特定的字符或子字符串,是一个极其常见且基础的操作。无论是处理用户输入、解析日志文件、过滤敏感词,还是进行数据校验,我们都可能遇到这样的需求。PHP提供了多种函数来完成这项任务,每种函数都有其独特的特点、适用场景和性能考量。作为一名专业的PHP开发者,理解这些方法的异同并选择最合适的工具至关重要。
本文将深入探讨PHP中判断字符串包含的各种方法,包括经典的`strpos()`、PHP 8+ 引入的 `str_contains()`、强大的正则表达式 `preg_match()` 等,并提供详细的代码示例、性能分析以及最佳实践建议,帮助您在实际开发中做出明智的选择。
一、最常用也是最经典的:`strpos()` / `stripos()`
`strpos()` 是PHP中判断字符串包含关系最常用且效率最高的函数之一。它用于查找目标字符串在源字符串中第一次出现的位置。如果找到,则返回该子字符串的起始位置(索引,从0开始);如果未找到,则返回 `false`。
1.1 `strpos()`:区分大小写查找
函数签名:
strpos(string $haystack, string $needle, int $offset = 0): int|false
`$haystack`:要搜索的字符串。
`$needle`:要在 `$haystack` 中查找的子字符串。
`$offset`:可选参数,指定从 `$haystack` 的哪个位置开始搜索,默认为0。
关键点:由于 `strpos()` 在找到子字符串时可能返回 `0`(表示子字符串位于字符串的开头),而 `0` 在PHP的弱类型比较中会被视为 `false`,所以我们必须使用严格的比较运算符 `!== false` 来判断是否找到子字符串,以避免潜在的逻辑错误。<?php
$text = "Hello, world! This is a PHP example.";
$search1 = "world";
$search2 = "php"; // 小写,由于strpos区分大小写,将找不到
$search3 = "PHP"; // 大写,可以找到
$search4 = "example";
// 查找 "world"
if (strpos($text, $search1) !== false) {
echo "<p>'{$text}' 包含 '{$search1}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'world'
} else {
echo "<p>'{$text}' 不包含 '{$search1}'</p>";
}
// 查找 "php" (区分大小写,找不到)
if (strpos($text, $search2) !== false) {
echo "<p>'{$text}' 包含 '{$search2}'</p>";
} else {
echo "<p>'{$text}' 不包含 '{$search2}'</p>"; // 输出:'Hello, world! This is a PHP example.' 不包含 'php'
}
// 查找 "PHP" (区分大小写,找到)
if (strpos($text, $search3) !== false) {
echo "<p>'{$text}' 包含 '{$search3}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'PHP'
} else {
echo "<p>'{$text}' 不包含 '{$search3}'</p>";
}
// 查找 "example" 从指定位置开始
if (strpos($text, $search4, 20) !== false) { // 从索引20开始搜索
echo "<p>'{$text}' 从索引20开始包含 '{$search4}'</p>"; // 输出:'Hello, world! This is a PHP example.' 从索引20开始包含 'example'
} else {
echo "<p>'{$text}' 从索引20开始不包含 '{$search4}'</p>";
}
// 示例:子字符串在开头的情况
$text_start = "apple banana orange";
$search_start = "apple";
if (strpos($text_start, $search_start) !== false) {
echo "<p>'{$text_start}' 包含 '{$search_start}',且在开头。</p>"; // 输出:'apple banana orange' 包含 'apple',且在开头。
}
?>
1.2 `stripos()`:不区分大小写查找
与 `strpos()` 类似,`stripos()` 的唯一区别在于它在搜索时会忽略大小写。这在需要进行大小写不敏感的匹配时非常有用。
函数签名:
stripos(string $haystack, string $needle, int $offset = 0): int|false<?php
$text = "Hello, world! This is a PHP example.";
$search_case_insensitive = "php";
// 查找 "php" (不区分大小写,可以找到)
if (stripos($text, $search_case_insensitive) !== false) {
echo "<p>'{$text}' 包含 (不区分大小写) '{$search_case_insensitive}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 (不区分大小写) 'php'
} else {
echo "<p>'{$text}' 不包含 (不区分大小写) '{$search_case_insensitive}'</p>";
}
?>
二、PHP 8+ 的现代之选:`str_contains()`
从 PHP 8.0 开始,PHP 引入了一个全新的函数 `str_contains()`,旨在提供一个更直观、更简洁的方式来判断字符串是否包含子字符串。它直接返回 `true` 或 `false`,避免了 `strpos()` 中 `!== false` 的潜在误解。
2.1 `str_contains()`:简洁直观的判断
函数签名:
str_contains(string $haystack, string $needle): bool
`$haystack`:要搜索的字符串。
`$needle`:要在 `$haystack` 中查找的子字符串。
关键点:
返回 `true` 或 `false`,无需严格比较。
区分大小写。
不提供 `offset` 参数。
<?php
$text = "Hello, world! This is a PHP example.";
$search1 = "world";
$search2 = "python";
$search3 = "PHP";
if (str_contains($text, $search1)) {
echo "<p>'{$text}' 包含 '{$search1}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'world'
} else {
echo "<p>'{$text}' 不包含 '{$search1}'</p>";
}
if (str_contains($text, $search2)) {
echo "<p>'{$text}' 包含 '{$search2}'</p>";
} else {
echo "<p>'{$text}' 不包含 '{$search2}'</p>"; // 输出:'Hello, world! This is a PHP example.' 不包含 'python'
}
if (str_contains($text, $search3)) {
echo "<p>'{$text}' 包含 '{$search3}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'PHP'
}
?>
2.2 `str_contains()` 的 PHP 7 及以下版本兼容方案 (Polyfill)
如果您在使用 PHP 8.0 以下的版本,但希望享受 `str_contains()` 的便利,可以自行实现一个兼容函数(polyfill)。<?php
if (!function_exists('str_contains')) {
function str_contains(string $haystack, string $needle): bool
{
return '' === $needle || false !== strpos($haystack, $needle);
}
}
// 现在在 PHP 7.x 环境中也能使用 str_contains 了
$text = "PHP is awesome.";
if (str_contains($text, "awesome")) {
echo "<p>使用 polyfill: '{$text}' 包含 'awesome'</p>"; // 输出:使用 polyfill: 'PHP is awesome.' 包含 'awesome'
}
?>
三、返回子字符串的函数:`strstr()` / `stristr()`
`strstr()` 和 `stristr()` 不仅能判断字符串是否包含子字符串,还能返回从子字符串第一次出现位置到源字符串结尾的部分。如果只需要判断是否存在,它们的功能与 `strpos()` 类似,但效率通常略低于 `strpos()`。
3.1 `strstr()`:区分大小写查找并返回
函数签名:
strstr(string $haystack, string $needle, bool $before_needle = false): string|false
`$haystack`:要搜索的字符串。
`$needle`:要在 `$haystack` 中查找的子字符串。
`$before_needle`:可选参数,如果设置为 `true`,则返回 `needle` 之前的部分;默认为 `false`,返回 `needle` 及之后的部分。
<?php
$text = "Hello, world! This is a PHP example.";
$search = "world";
$result = strstr($text, $search);
if ($result !== false) {
echo "<p>'{$text}' 包含 '{$search}'。匹配结果: '{$result}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'world'。匹配结果: 'world! This is a PHP example.'
} else {
echo "<p>'{$text}' 不包含 '{$search}'</p>";
}
$result_before = strstr($text, $search, true);
if ($result_before !== false) {
echo "<p>'{$text}' 包含 '{$search}'。匹配结果 (之前部分): '{$result_before}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 'world'。匹配结果 (之前部分): 'Hello, '
}
?>
3.2 `stristr()`:不区分大小写查找并返回
`stristr()` 与 `strstr()` 功能相同,但它在搜索时会忽略大小写。<?php
$text = "Hello, world! This is a PHP example.";
$search = "PHP";
$result = stristr($text, "php"); // 不区分大小写查找 "php"
if ($result !== false) {
echo "<p>'{$text}' 包含 (不区分大小写) 'php'。匹配结果: '{$result}'</p>"; // 输出:'Hello, world! This is a PHP example.' 包含 (不区分大小写) 'php'。匹配结果: 'PHP example.'
}
?>
四、统计子字符串出现次数:`substr_count()`
`substr_count()` 用于计算子字符串在目标字符串中出现的次数。如果返回的计数大于0,则说明目标字符串包含该子字符串。
函数签名:
substr_count(string $haystack, string $needle, int $offset = 0, ?int $length = null): int
`$haystack`:要搜索的字符串。
`$needle`:要查找的子字符串。
`$offset`:可选参数,开始搜索的位置。
`$length`:可选参数,在 `$haystack` 中搜索的最大长度。
关键点:
默认区分大小写。
它不会处理重叠的子字符串(例如,在 "aaaaa" 中查找 "aaa" 会返回 1 而不是 3)。
<?php
$text = "apple banana apple orange apple";
$search = "apple";
$count = substr_count($text, $search);
if ($count > 0) {
echo "<p>'{$text}' 包含 '{$search}',出现 {$count} 次。</p>"; // 输出:'apple banana apple orange apple' 包含 'apple',出现 3 次。
} else {
echo "<p>'{$text}' 不包含 '{$search}'</p>";
}
// 区分大小写示例
$text2 = "PHP is a php language.";
$search2 = "php";
$count2 = substr_count($text2, $search2);
echo "<p>'{$text2}' 中 '{$search2}' 出现 {$count2} 次 (区分大小写)。</p>"; // 输出:'PHP is a php language.' 中 'php' 出现 1 次 (区分大小写)。
?>
五、正则表达式的强大:`preg_match()`
当需要更复杂的匹配模式时,例如查找符合特定格式的子字符串、匹配多个可能的子字符串,或者执行不区分大小写的匹配,`preg_match()` 函数配合正则表达式是最佳选择。虽然它的性能通常低于 `strpos()` 等简单字符串函数,但其灵活性是无与伦比的。
函数签名:
preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int|false
`$pattern`:要搜索的正则表达式模式。
`$subject`:要搜索的字符串。
`$matches`:可选参数,一个数组,如果提供了,它将被填充为所有匹配结果。
`$flags`:可选参数,用于控制匹配行为(例如 `PREG_OFFSET_CAPTURE`)。
`$offset`:可选参数,指定从 `$subject` 的哪个位置开始搜索。
关键点:
如果找到匹配项,返回 `1`;未找到,返回 `0`;发生错误,返回 `false`。
模式必须用定界符(如 `/`、`#`、`~` 等)包围。
可以使用各种修饰符(如 `i` 不区分大小写,`g` 全局匹配,尽管 `preg_match` 默认只匹配一次)。
<?php
$text = "Hello, world! This is a PHP example. The year is 2023.";
// 1. 简单查找 "world" (区分大小写)
if (preg_match('/world/', $text)) {
echo "<p>'{$text}' 包含 'world' (通过正则)。</p>"; // 输出:'Hello, world! This is a PHP example. The year is 2023.' 包含 'world' (通过正则)。
}
// 2. 查找 "php" (不区分大小写,使用 'i' 修饰符)
if (preg_match('/php/i', $text)) {
echo "<p>'{$text}' 包含 'php' (不区分大小写,通过正则)。</p>"; // 输出:'Hello, world! This is a PHP example. The year is 2023.' 包含 'php' (不区分大小写,通过正则)。
}
// 3. 查找是否包含 "Hello" 或 "Goodbye"
if (preg_match('/Hello|Goodbye/', $text)) {
echo "<p>'{$text}' 包含 'Hello' 或 'Goodbye' (通过正则)。</p>"; // 输出:'Hello, world! This is a PHP example. The year is 2023.' 包含 'Hello' 或 'Goodbye' (通过正则)。
}
// 4. 查找数字 (使用 \d+ )
if (preg_match('/\d+/', $text, $matches)) {
echo "<p>'{$text}' 包含数字。第一个数字是: {$matches[0]}</p>"; // 输出:'Hello, world! This is a PHP example. The year is 2023.' 包含数字。第一个数字是: 2023
} else {
echo "<p>'{$text}' 不包含数字。</p>";
}
?>
六、性能考量与选择建议
选择正确的字符串包含判断函数,不仅关乎代码的简洁性,还可能影响程序的性能,尤其是在处理大量数据或高并发请求时。
`str_contains()` (PHP 8.0+):
优点:最简洁、最直观、最符合语义的函数,性能与 `strpos()` 相当或略优。
缺点:仅适用于 PHP 8.0 及更高版本。区分大小写,不提供 `offset` 参数。
建议:如果您的项目运行在 PHP 8.0+,且需要进行区分大小写的简单子字符串判断,首选 `str_contains()`。
`strpos()` / `stripos()`:
优点:效率极高,性能最佳。`strpos()` 区分大小写,`stripos()` 不区分大小写。支持 `offset` 参数。
缺点:需要使用 `!== false` 进行严格比较,代码可读性略逊于 `str_contains()`。
建议:如果您的项目运行在 PHP 7.x 或更早版本,或者需要 `offset` 参数,`strpos()` / `stripos()` 是最佳选择。
`strstr()` / `stristr()`:
优点:除了判断是否存在,还能返回匹配到的子字符串及其后的部分(或之前的部分)。
缺点:如果仅仅是判断存在性,性能略低于 `strpos()` 系列。
建议:当您不仅需要判断是否存在,还需要获取匹配子字符串之后(或之前)的文本时,使用它们。
`substr_count()`:
优点:可以统计子字符串出现的次数。
缺点:如果仅仅是判断存在性,其性能通常不如 `strpos()`。不处理重叠子字符串。
建议:当您需要知道子字符串出现了多少次时使用。如果只是判断是否存在,且对性能有要求,`strpos()` 更佳。
`preg_match()`:
优点:极其灵活,可以处理复杂的匹配模式(如正则表达式),支持不区分大小写、多模式匹配等。
缺点:正则表达式的解析和匹配过程通常比简单字符串查找的性能开销更大。对于简单需求,使用它会造成不必要的性能浪费。
建议:只有当您的匹配逻辑无法通过简单字符串函数实现时,才考虑使用 `preg_match()`。例如,匹配邮箱格式、URL模式、包含任意数字或特定字符范围等。
七、常见陷阱与最佳实践
`strpos()` 的 `!== false`:
这是一个最常见的错误源。始终使用 `!== false` 来判断 `strpos()` 或 `stripos()` 的返回值,而不是 `!= false` 或直接将返回值作为布尔值使用。 <?php
$text = "0 is a number";
$search = "0";
// 错误示范:
if (strpos($text, $search)) { // strpos返回0,被当做false
echo "包含 '{$search}' (错误判断)";
} else {
echo "不包含 '{$search}' (错误判断)"; // 会输出此行
}
// 正确示范:
if (strpos($text, $search) !== false) {
echo "包含 '{$search}' (正确判断)"; // 会输出此行
} else {
echo "不包含 '{$search}' (正确判断)";
}
?>
空字符串作为查找目标 (`$needle`):
`strpos()` / `stripos()`:如果 `$needle` 是一个空字符串 `""`,它们会返回 `0`(表示在字符串开头找到)。这意味着一个空字符串总是被认为包含在任何非空字符串的开头。
`str_contains()`:如果 `$needle` 是一个空字符串 `""`,`str_contains()` 会返回 `true`。
`preg_match()`:如果 `$pattern` 为空,会引发警告或错误。
在实际应用中,通常会避免使用空字符串作为查找目标,或者在调用前进行检查。
编码问题:
对于多字节字符(如中文、日文等),`strpos()` 等函数可能无法正确处理。在这种情况下,您应该使用多字节字符串函数,如 `mb_strpos()`、`mb_stripos()` 等。这些函数需要 `mbstring` 扩展的支持。 <?php
$text_mb = "你好世界,这是一个PHP示例。";
$search_mb = "世界";
// 使用mb_strpos处理多字节字符
if (mb_strpos($text_mb, $search_mb) !== false) {
echo "<p>'{$text_mb}' 包含 '{$search_mb}' (使用mb_strpos)。</p>"; // 输出:'你好世界,这是一个PHP示例。' 包含 '世界' (使用mb_strpos)。
}
?>
避免不必要的正则表达式:
如果简单字符串函数(如 `strpos()` 或 `str_contains()`)能够满足需求,就不要使用 `preg_match()`。正则表达式的开销更大,可读性也相对较差。
PHP版本兼容性:
在编写可移植的代码时,注意 `str_contains()` 仅适用于 PHP 8.0+。如果需要兼容旧版本,请使用 `strpos()` 及其 `!== false` 模式,或提供一个 polyfill。
PHP提供了丰富且功能各异的函数来判断字符串是否包含子字符串。从基础的 `strpos()` 到 PHP 8.0+ 提供的 `str_contains()`,再到功能强大的 `preg_match()`,每种方法都有其特定的使用场景和优缺点。
对于简单的、区分大小写的判断(PHP 8.0+),`str_contains()` 是最推荐的选择。
对于简单的、区分大小写的判断(PHP 7.x 及以下),或者需要指定起始位置,`strpos()` 配合 `!== false` 是最佳选择。
对于简单的、不区分大小写的判断,`stripos()` 是最高效的方法。
当需要获取匹配子字符串的部分文本时,可以考虑使用 `strstr()` 或 `stristr()`。
当需要统计子字符串出现次数时,使用 `substr_count()`。
当需要复杂的模式匹配、模糊匹配或组合条件时,`preg_match()` 结合正则表达式是唯一选择。
处理多字节字符时,请务必使用 `mb_` 系列函数,如 `mb_strpos()`。
作为一名专业的PHP程序员,理解并熟练运用这些函数是必备技能。根据具体需求权衡性能、可读性、功能和兼容性,选择最合适的工具,将使您的代码更加高效、健壮和易于维护。
2025-10-20

Python数据仿真:从基础到高级,构建智能系统与模型训练的利器
https://www.shuihudhg.cn/130381.html

Python sys 模块与文件操作深度解析:掌控标准流、命令行参数与文件系统交互
https://www.shuihudhg.cn/130380.html

PHP文件深度解析:从代码查看、编辑到执行与调试的全方位指南
https://www.shuihudhg.cn/130379.html

Java转义字符深度解析:从基础到高级应用
https://www.shuihudhg.cn/130378.html

Python高阶函数:将函数作为参数传递的艺术与实践
https://www.shuihudhg.cn/130377.html
热门文章

在 PHP 中有效获取关键词
https://www.shuihudhg.cn/19217.html

PHP 对象转换成数组的全面指南
https://www.shuihudhg.cn/75.html

PHP如何获取图片后缀
https://www.shuihudhg.cn/3070.html

将 PHP 字符串转换为整数
https://www.shuihudhg.cn/2852.html

PHP 连接数据库字符串:轻松建立数据库连接
https://www.shuihudhg.cn/1267.html