php implode explode,[PHP源码阅读]explode和implode函数
explode和implode函数主要用作字符串和数组间转换的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出。在PHP中经常会用到这两个函数,因此有必要了解一下其原理。
我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。
explode
array explode ( string $delimiter, string $string, [ , $limit ] )
函数返回由字符串组成的数组,每个元素都是string的一个子串,被字符串$delimiter作为边界点分割出来。
参数说明
limit
如果设置了limit,且为正数,则返回的数组最多包含limit个元素,最后的那个元素将包含string的剩余部分。
如果limit是负数,则返回除了最后的-$limit个元素外的所有元素。
如果limit是0,则会被当做1。
delimiter
如果delimiter为空,则函数返回FALSE。如果delimiter不在string中,且limit为负数,则返回空数组。
运行示例
$str = 'hello,world,heiheihei,php';
先来看看不设置limit的情况
$arr = explode(',', $str);
print_r($arr);
limit为正数时,limit设为1,最多返回1个元素。
$arr = explode(',', $str, 1);
print_r($arr);
limit为负数,limit为-1,返回最后的1个元素外的所有元素。
$arr = explode(',', $str, -1);
print_r($arr);
limit为0,当作1处理。
$arr = explode(',', $str, 0);
print_r($arr);
explode执行步骤
1、接收参数,处理参数为空的情况
2、创建函数中使用的局部变量
3、根据limit的值调用不同的函数分隔字符串
explode函数的核心实现是php_explode函数,下面是该函数的执行流程图:
php_explode函数核心代码:
if (p2 == NULL) {
// 找不到分隔符,直接返回整个字符串
add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
} else {
do {
// 将p1添加到return_value数组中
add_next_index_stringl(return_value, p1, p2 - p1, 1);
p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
--limit > 1);
// 将最后一个值添加到return_value
if (p1 <= endp)
add_next_index_stringl(return_value, p1, endp-p1, 1);
}
源码解读
sizeof("") == 0。sizeof有两种用法,sizeof(typename)和sizeof(expression),当参数为typename是,即类型名称,sizeof返回类型对应对象的大小;当参数为表达式时,sizeof计算表达式的返回类型对应对象的大小。此处,""是表达式,sizeof计算编译时编译器分配给""的空间,此时要算上0的长度,因此是1,而strlen函数不会计算\0。
如果不设置limit,limit的默认值是LONG_MAX。在php.h文件中,LONG_MAX定义为2147483647L。
在实现里面,如果limit大于1,则调用php_explode函数;如果limit小于0,则调用php_explode_negative_limit函数;如果limit等于0,则被当做1处理,此时调用add_index_stringl函数将str添加到数组return_value中。
在查找分隔符delimiter时,调用了php_memnstr函数
php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
而php_memnstr是zend_memnstr的宏定义,zend_memnstr实现里面,因此实际上是调用了C里面的memchr来查找字符delimiter。
找到分隔符的位置之后,就调用add_next_index_stringl函数将分隔得到的字符串插入到返回数组里。
implode
string implode ( string $glue, array $pieces )
string implode ( array $pieces )
将一个一维数组的值转换为字符串
参数说明
implode函数可以接收两种参数顺序。另外,如果第一个参数为数组而第二个参数为空,则第二个参数为默认值''。此函数可以看作是explode的逆向过程。
当然,使用文档规定的顺序可避免混淆。
运行示例
$arr = array('hello', 'world');
按照文档顺序参数
$str = implode('-‘, $arr);// 输出"hello-world"
第一个参数为数组
$str = implode($arr); // 输出"helloworld"
$str = implode($arr, '-'); // 输出"hello-world"
implode执行步骤
1、接收参数并赋值
2、如果第二个参数为空,则判断第一个参数的类型是否为数组,如果不是,则报错。否则,则使用""对glue赋值,使用其作为连接符。
3、如果第二个参数不为空,那么,如果第一个参数是数组类型,则将第二个参数转换成字符串类型;否则,如果第二个参数是数组类型,则将第一个参数转换成字符串类型。
4、调用php_implode函数做字符串的连接。
在implode函数设置完参数之后,底层就调用php_implode函数进行字符串连接,php_implode函数的执行流程图如下:
php_implode函数核心代码:
// 遍历数组的每一个元素,判断其类型,然后调用smart_str_appendl函数将值追加到字符串中
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) {
switch ((*tmp)->type) {
case IS_STRING:
smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
break;
case IS_LONG: {
char stmp[MAX_LENGTH_OF_LONG + 1];
str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp));
smart_str_appendl(&implstr, stmp, str_len);
}
break;
case IS_BOOL:
if (Z_LVAL_PP(tmp) == 1) {
smart_str_appendl(&implstr, "1", sizeof("1")-1);
}
break;
case IS_NULL:
break;
case IS_DOUBLE: {
char *stmp;
str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp));
smart_str_appendl(&implstr, stmp, str_len);
efree(stmp);
}
break;
case IS_OBJECT: {
int copy;
zval expr;
zend_make_printable_zval(*tmp, &expr, ©);
smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr));
if (copy) {
zval_dtor(&expr);
}
}
break;
default:
tmp_val = **tmp;
zval_copy_ctor(&tmp_val);
convert_to_string(&tmp_val);
smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
zval_dtor(&tmp_val);
break;
}
// 添加glue字符
if (++i != numelems) {
smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
}
zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
}
// 在尾部添加结束字符0
smart_str_0(&implstr);
源码解读
php_implode会逐个获取数组里面的内容,然后判断每个元素的类型,再做必要的数据类型转换之后,调用smart_str_appendl函数将值追加到返回的字符串后面。最后,还要在字符串后面加上结束符,这是个必须的操作,以后编程时也应注意。
小结
暂且写这么多,还有更多的优化和PHP源码中常用的函数,将会在以后的源码阅读中慢慢讲述。
原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
如果本文对你有帮助,请点下推荐吧,谢谢^_^
最后再安利一下,我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。
php implode explode,[PHP源码阅读]explode和implode函数相关推荐
- nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数
前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...
- php函数阅读,[PHP源码阅读]strtolower和strtoupper函数
字符串的操作函数中,字符串的大小写转换也算是比较常用的函数,其底层实现也比较简单,下面来一探究竟. 我在github上有对PHP源码更详细的注解.感兴趣的可以围观一下,给个star. PHP5.4源码 ...
- [PHP源码阅读]strtolower和strtoupper函数
字符串的操作函数中,字符串的大小写转换也算是比较常用的函数,其底层实现也比较简单,下面来一探究竟. 我在github上有对PHP源码更详细的注解.感兴趣的可以围观一下,给个star.PHP5.4源码注 ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...
- 应用监控CAT之cat-client源码阅读(一)
CAT 由大众点评开发的,基于 Java 的实时应用监控平台,包括实时应用监控,业务监控.对于及时发现线上问题非常有用.(不知道大家有没有在用) 应用自然是最初级的,用完之后,还想了解下其背后的原理, ...
- centos下将vim配置为强大的源码阅读器
每日杂事缠身,让自己在不断得烦扰之后终于有了自己的清静时光来熟悉一下我的工具,每次熟悉源码都需要先在windows端改好,拖到linux端,再编译.出现问题,还得重新回到windows端,这个过程太耗 ...
- 源码阅读:AFNetworking(十六)——UIWebView+AFNetworking
该文章阅读的AFNetworking的版本为3.2.0. 这个分类提供了对请求周期进行控制的方法,包括进度监控.成功和失败的回调. 1.接口文件 1.1.属性 /**网络会话管理者对象*/ @prop ...
- 源码阅读:SDWebImage(六)——SDWebImageCoderHelper
该文章阅读的SDWebImage的版本为4.3.3. 这个类提供了四个方法,这四个方法可分为两类,一类是动图处理,一类是图像方向处理. 1.私有函数 先来看一下这个类里的两个函数 /**这个函数是计算 ...
- mybatis源码阅读
说下mybatis执行一个sql语句的流程 执行语句,事务等SqlSession都交给了excutor,excutor又委托给statementHandler SimpleExecutor:每执行一次 ...
- 24 UsageEnvironment使用环境抽象基类——Live555源码阅读(三)UsageEnvironment
24 UsageEnvironment使用环境抽象基类--Live555源码阅读(三)UsageEnvironment 24 UsageEnvironment使用环境抽象基类--Live555源码阅读 ...
最新文章
- 硬链接、软链接和inode
- xp主机用VMware9和10安装Ubuntu12.04后无法进入图像界面
- 博客创办目的——————欢迎相互学习
- read name 和 read 在 Bash 中的区别
- 【C++深度剖析教程34】C++中的强制类型转换dynamic_cast
- 离职交接文档_离职程序员交接工作被同事怒怼:每一行代码都讲清楚,不然投诉你...
- “哎哟,真的很快哦” 闪送宣布签约周杰伦为其品牌代言人
- Dogeswap上线18小时TVL突破300万美金
- UINavigationItem 设置UIBarButtonItem
- 如何把一张图片设置成一个应用程序的图标?
- canvas抖音八卦时钟,轻喷
- 计算机word大作业,计算机操作基础--Word大作业要求.doc
- Winform contextmenustrip 隐藏图标区域
- 这个emoji表情可使iphone变砖
- win7 任务栏 通知区域
- 【下载Tomcat旧版本】
- html元素的overflow属性详解
- EMQ X 插件持久化系列 (五)MySQL MQTT 数据存储
- Linus下EDB的安装
- Anaconda:The environment is inconsistent, please check the package plan carefully问题的解决办法
热门文章
- Java学Web——day09【SQL多表联合查询】
- JVM虚拟机与Android虚拟机
- erp系统的优点和不足?云系统给企业带来的好处?
- C#实战之CAD二次开发002:绘制直线和绘制圆
- LOJ2312 LUOGU-P3733「HAOI2017」八纵八横 (异或线性基、生成树、线段树分治)
- 中国八横八纵大容量光纤通信网——世界级光纤通信网
- Shake Shack上海第7家门店开业
- java连接redis设置密码_jedis设置密码连接Redis
- android emmc测试软件,鉴别EMMC/UFS如此简单!小工具一键识别闪存
- 为什么我们的数据还不够开放?