目录
strpos
例子
strpos核心源码
查找函数
strstr
strstr核心源码
stripos
stristr
核心源码
总结
打赏支持作者写出更多好文章,谢谢!
关于作者:hoohack
首页 后端开发 php教程 PHP源码阅读:strpos、strstr、stripos、stristr函数

PHP源码阅读:strpos、strstr、stripos、stristr函数

Jun 20, 2016 pm 12:27 PM

我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。

strpos

mixed strpos ( string $haystack, mixed $needle [, int $offset = 0 ] )
登录后复制

如果offset指定了,查找会从offset的位置开始。offset不能为负数。

返回needle第一次出现在haystack的位置。如果在haystack中找不到needle,则返回FALSE。

needle,如果needle不是字符串,它会被转换成整型数值并赋值为该数值的ASCII字符。请看下面例子。

例子

$str = "hello";$pos = strpos($str, 111);// 111的ASCII值是o,因此$pos = 4
登录后复制

strpos核心源码

if (Z_TYPE_P(needle) == IS_STRING) {     if (!Z_STRLEN_P(needle)) {          php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");          RETURN_FALSE;     }     // 调用php_memnstr函数查找needle     found = php_memnstr(haystack + offset,                            Z_STRVAL_P(needle),                            Z_STRLEN_P(needle),                            haystack + haystack_len);     } else {          // 如果不是字符串,转换成数字并赋值为该数字的ASCII字符。          if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {               RETURN_FALSE;          }          //设置结束字符          needle_char[1] = 0;          found = php_memnstr(haystack + offset,                            needle_char,                            1,                            haystack + haystack_len);    }}
登录后复制

有一点要注意的是,如果needle不是字符串的话,会调用php_needle_char函数将needle转成整型数字并转换为其ASCII值。

查找函数

函数最后返回的是found,php_memnstr函数实现了查找的方法。那么再继续看看php_memnstr函数做了什么:

#define php_memnstr zend_memnstr
登录后复制

php_memnstr是函数zend_memnstr的宏定义,查看zend_memnstr函数如下:

static inline char *zend_memnstr(char *haystack, char *needle, int needle_len, char *end){    char *p = haystack;    char ne = needle[needle_len-1];    if (needle_len == 1) {        return (char *)memchr(p, *needle, (end-p));    }    if (needle_len > end-haystack) {        return NULL;    }    // 第一个优化,只查找end - needle_len次    end -= needle_len;    while (p <= end) {        // 第二个优化,先判断字符串的开头和结尾是否一样再判断整个字符串        if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {            if (!memcmp(needle, p, needle_len-1)) {                return p;            }        }        if (p == NULL) {            return NULL;        }        p++;    }    return NULL;}
登录后复制

第一个优化,因为(char *)memchr(p, *needle, (end-p+1)是在end – needle_len + 1(即haystack_len+1)中查找,如果p为空,说明needle的第一个字符在p中从未出现过。

strstr

string strstr ( string $haystack, mixed $needle [, bool $before_needle = false ] ) 返回needle在haystack中第一次出现的位置到结束的字符串。
登录后复制

这个函数的区分大小写的。

如果needle在haystack中不存在,返回FALSE。

如果before_needle为true,则返回haystack中needle在haystack第一次出现的位置之前的字符串。

strstr核心源码

if (found) {        // 计算出found的位置        found_offset = found - haystack;        if (part) {            RETURN_STRINGL(haystack, found_offset, 1);        } else {            RETURN_STRINGL(found, haystack_len - found_offset, 1);        }}
登录后复制

strstr函数的前半部分跟strpos类似,区别在于strstr函数在找到位置后,需要返回haystack部分的字符串。part变量就是调用strstr函数时传递的before_needle变量。

stripos

mixed stripos ( string $haystack, string $needle [, int $offset = 0 ] ) 不区分大小写的strpos。实现方式跟下面的类似,主要是使用一份拷贝然后将需要比较的字符串转换成小写字符后进行再进行查找。
登录后复制

stristr

string stristr ( string $haystack, mixed $needle [, bool $before_needle = false ] ) 不区分大小写的strstr。
登录后复制

核心源码

// 拷贝一份haystackhaystack_dup = estrndup(haystack, haystack_len);if (Z_TYPE_P(needle) == IS_STRING) {    char *orig_needle;    if (!Z_STRLEN_P(needle)) {        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");        efree(haystack_dup);        RETURN_FALSE;    }    orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));    // 调用php_stristr函数找出orig_needle的值。    found = php_stristr(haystack_dup, orig_needle,    haystack_len, Z_STRLEN_P(needle));    efree(orig_needle);} else {    if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {        efree(haystack_dup);        RETURN_FALSE;    }    needle_char[1] = 0;    found = php_stristr(haystack_dup, needle_char,    haystack_len, 1);}if (found) {    found_offset = found - haystack_dup;    if (part) {        RETVAL_STRINGL(haystack, found_offset, 1);    } else {        RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);    }} else {    RETVAL_FALSE;}// 释放变量efree(haystack_dup);
登录后复制

可以知道,found是从php_stristr中得到的,继续查看php_stristr函数:

PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len){    php_strtolower(s, s_len);    php_strtolower(t, t_len);    return php_memnstr(s, t, t_len, s + s_len);} 
登录后复制

这个函数的功能就是将字符串都转成小写之后调用php_mennstr函数来查找needle在haystack第一次出现的位置。

总结

因为strpos/stripos返回的是位置,位置从0开始计算,所以判断查找失败都用=== FALSE更适合。

阅读PHP的源码收获挺多,一方面可以知道某个函数的具体实现原理是怎样的,另一方面可以学习到一些编程优化方案。

到此本文结束,如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

最后再安利一下,我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。

打赏支持作者写出更多好文章,谢谢!

打赏作者

打赏支持作者写出更多好文章,谢谢!

任选一种支付方式

关于作者:hoohack

一个正在努力的菜鸟 个人主页 · 我的文章 · 3 ·          

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌
威尔R.E.P.O.有交叉游戏吗?
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

在PHP API中说明JSON Web令牌(JWT)及其用例。 在PHP API中说明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

描述扎实的原则及其如何应用于PHP的开发。 描述扎实的原则及其如何应用于PHP的开发。 Apr 03, 2025 am 12:04 AM

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

解释PHP中晚期静态结合的概念。 解释PHP中晚期静态结合的概念。 Mar 21, 2025 pm 01:33 PM

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

如何在系统重启后自动设置unixsocket的权限? 如何在系统重启后自动设置unixsocket的权限? Mar 31, 2025 pm 11:54 PM

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

如何用PHP的cURL库发送包含JSON数据的POST请求? 如何用PHP的cURL库发送包含JSON数据的POST请求? Apr 01, 2025 pm 03:12 PM

使用PHP的cURL库发送JSON数据在PHP开发中,经常需要与外部API进行交互,其中一种常见的方式是使用cURL库发送POST�...

框架安全功能:防止漏洞。 框架安全功能:防止漏洞。 Mar 28, 2025 pm 05:11 PM

文章讨论了框架中的基本安全功能,以防止漏洞,包括输入验证,身份验证和常规更新。

自定义/扩展框架:如何添加自定义功能。 自定义/扩展框架:如何添加自定义功能。 Mar 28, 2025 pm 05:12 PM

本文讨论了将自定义功能添加到框架上,专注于理解体系结构,识别扩展点以及集成和调试的最佳实践。

See all articles