[PHP源码阅读]explode和implode函数,explodeimplode

explode和implode函数主要用作字符串-数组的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出。在PHP中经常会用到这两个函数,因此有必要了解一下其原理。

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为负数,则返回空数组。

核心源码

//如果delimiter为空字符串,返回FALSE

if (delim_len == 0) {

php_error_docref(NULL TSRMLS_CC, E_WARNING,"Empty delimiter");

RETURN_FALSE;

}//初始化返回的数组

array_init(return_value);if (str_len == 0) {if (limit >= 0) {//如果字符串为空且limit大于等于0,则返回一个包含空字符串的数组,注意此处sizeof("") == 1

add_next_index_stringl(return_value, "", sizeof("") - 1, 1);

}return;

}//初始化zstr和zdelim的字符串变量

ZVAL_STRINGL(&zstr, str, str_len, 0);

ZVAL_STRINGL(&zdelim, delim, delim_len, 0);if (limit > 1) {//limit大于1,limit默认是LONG_MAX

php_explode(&zdelim, &zstr, return_value, limit);

}else if (limit < 0) {//limit 为负数

php_explode_negative_limit(&zdelim, &zstr, return_value, limit);

}else{//limit为0,被当作1处理,返回整个字符串,add_index_stringl函数将str追加到数组return_value中

add_index_stringl(return_value, 0, str, str_len, 1);

}

处理完特殊情况和初始化变量后,就调用php_explode/php_explode_negative_limit函数进行下一步处理。下面是php_explode函数的源码

php_explode

endp= Z_STRVAL_P(str) +Z_STRLEN_P(str);//p1指向字符串的开始

p1 =Z_STRVAL_P(str);//p2指向第一个分隔符的位置 ,找出分隔符位置主要用的是php_memnstr函数

p2 =php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);if (p2 ==NULL) {//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);

}=

实现时调用了add_next_index_stringl将得到的每个字符串添加到数组return_value中。add_next_index_string是此功能的核心函数。

ZEND_API int add_next_index_stringl(zval *arg, const char *str, uint length, intduplicate)

{

zval*tmp;

MAKE_STD_ZVAL(tmp);

ZVAL_STRINGL(tmp, str, length, duplicate);return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, sizeof(zval *), NULL);

}

add_next_index_stringl函数调用zend_hash_next_index_insert函数将str插入到数组中。再看看php_explode_negative_limit函数的源码

php_explode_negative_limit

//如果delimiter不在string中,且limit为负数,什么都不做,返回空的array,p2为NULL表示delimiter不在string中

if (p2 ==NULL) {/*

如果limit <= 1="" -1,那么什么都不做,因此如果只有一个字符串,那么-="" +="" (limit)="" <="0

返回空数组*/}else{int allocated = EXPLODE_ALLOC_STEP, found = 0;longi, to_return;char **positions = emalloc(allocated * sizeof(char *));//第一个单词的位置

positions[found++] =p1;do{if (found >=allocated) {

allocated= found + EXPLODE_ALLOC_STEP;/*保证有足够的内存空间*/positions= erealloc(positions, allocated*sizeof(char *));

}//positions保存每个单词的起始位置

positions[found++] = p1 = p2 +Z_STRLEN_P(delim);

}while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) !=NULL);//to_return 是return_value的数量,其实等于found - |limit|

to_return = limit +found;/*limit至少是-1,因此不需要边界检查:i永远小于found*/

for (i = 0;i < to_return;i++) { /*这个检查是检查to_return大于0*/add_next_index_stringl(return_value, positions[i],

(positions[i+1] - Z_STRLEN_P(delim)) -positions[i],1);

}

efree(positions);

}

php_explode_negative_limit也是跟php_implode类似的操作,找到分隔的字符串之后,调用add_next_index_string函数将limit + found个字符串添加到return_value数组中。

implode

string implode ( string $glue, array $pieces )

string implode ( array $pieces )

将一个一维数组的值转换为字符串

implode函数可以接收两种参数顺序。

核心代码

if (arg2 ==NULL) {//第二个参数为空,第一个参数必须为数组

if (Z_TYPE_PP(arg1) !=IS_ARRAY) {

php_error_docref(NULL TSRMLS_CC, E_WARNING,"Argument must be an array");return;

}

MAKE_STD_ZVAL(delim);#define _IMPL_EMPTY ""

//默认使用""连接

ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0);

SEPARATE_ZVAL(arg1);

arr= *arg1;

}else{//根据参数类型设置参数的值

if (Z_TYPE_PP(arg1) ==IS_ARRAY) {

arr= *arg1;

convert_to_string_ex(arg2);

delim= *arg2;

}else if (Z_TYPE_PP(arg2) ==IS_ARRAY) {

arr= *arg2;

convert_to_string_ex(arg1);

delim= *arg1;

}else{

php_error_docref(NULL TSRMLS_CC, E_WARNING,"Invalid arguments passed");return;

}

}//调用php_implode函数进行转换

php_implode(delim, arr, return_value TSRMLS_CC);

在底层实现中,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) {caseIS_STRING:

smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));break;caseIS_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;caseIS_BOOL:if (Z_LVAL_PP(tmp) == 1) {

smart_str_appendl(&implstr, "1", sizeof("1")-1);

}break;caseIS_NULL:break;caseIS_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;caseIS_OBJECT: {intcopy;

zval expr;

zend_make_printable_zval(*tmp, &expr, &copy);

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函数将值追加到字符串中。smart_str_appendl是implode实现代码中的核心函数。

smart_str_appendl

#define smart_str_appendl(dest, src, len) smart_str_appendl_ex((dest), (src), (len),0)#define smart_str_appendl_ex(dest, src, nlen, what) do { register size_t __nl;

smart_str*__dest = (smart_str *) (dest);

smart_str_alloc4(__dest, (nlen), (what), __nl);

memcpy(__dest->c + __dest->len, (src), (nlen));

__dest->len =__nl;

}while (0)

smart_str_appendl_ex主要调用memcpy函数进行字符串复制。

原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,点个推荐吧,谢谢^_^。

更多PHP源码阅读文章:

[PHP源码阅读]strlen函数

[PHP源码阅读]strpos、strstr和stripos、stristr函数

www.bkjia.comtrueTechArticle[PHP源码阅读]explode和implode函数,explodeimplode explode和implode函数主要用作字符串-数组的操作,比如获取一段参数后根据某个字符分割字符串,…

php打implode 函数,[PHP源码阅读]explode和implode函数,explodeimplode_PHP教程相关推荐

  1. nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数

    前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...

  2. php函数阅读,[PHP源码阅读]strtolower和strtoupper函数

    字符串的操作函数中,字符串的大小写转换也算是比较常用的函数,其底层实现也比较简单,下面来一探究竟. 我在github上有对PHP源码更详细的注解.感兴趣的可以围观一下,给个star. PHP5.4源码 ...

  3. [PHP源码阅读]strtolower和strtoupper函数

    字符串的操作函数中,字符串的大小写转换也算是比较常用的函数,其底层实现也比较简单,下面来一探究竟. 我在github上有对PHP源码更详细的注解.感兴趣的可以围观一下,给个star.PHP5.4源码注 ...

  4. java的resize函数_Java源码解析HashMap的resize函数

    hashmap的resize函数,用于对hashmap初始化或者扩容. 首先看一下该函数的注释,如下图.从注释中可以看到,该函数的作用是初始化或者使table的size翻倍.如果table是null, ...

  5. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是"引导"文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http:// ...

  6. django源码阅读 manage.py文件

    Django源码阅读之manager.py文件阅读 我们知道,我们运行一个django项目的时候,需要进入项目的根目录,然后输入命令,python manage.py runserver,这样,我们就 ...

  7. [PHP源码阅读]trim、rtrim、ltrim函数

    trim系列函数是用于去除字符串中首尾的空格或其他字符.ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符. 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下 ...

  8. 阅读react-redux源码(二) - createConnect、match函数的实现

    阅读react-redux源码 - 零 阅读react-redux源码 - 一 阅读react-redux源码(二) - createConnect.match函数的实现 上一节看了Provider组 ...

  9. wrappers.php,PHP源码阅读笔记六:stream_get_wrappers函数

    PHP源码阅读笔记stream_get_wrappers函数 stream_get_wrappers (PHP 5) stream_get_wrappers - 返回注册的数据流列表 Descript ...

  10. trim函数 php,[PHP源码阅读]trim、rtrim、ltrim函数

    trim系列函数是用于去除字符串中首尾的空格或其他字符.ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符. 我在github有对PHP源码更详细的注解.感兴趣的可以围观一下 ...

最新文章

  1. SAP MM PR 审批中的REJECT
  2. 开源 java CMS - FreeCMS2.8 栏目页静态化参数
  3. 【设计模式】迪米特法则和六种原则的总结
  4. Python:构造函数和析构函数
  5. 八、深入Go 编程语言接口
  6. map初始化_您可曾这样初始化一个map呢?
  7. 【测试基础】测试用例的设计方法
  8. 四因素三水平正交试验表_测试用例设计方法(二)——正交实验法
  9. [Android自定义控件] Android自定义控件
  10. C++:利用泰勒公式求cos x近似值
  11. 数据挖掘之数据处理——SVM神经网络的数据分类预测-意大利葡萄酒种类识别
  12. 刷新BIOS应该做的几件事
  13. FZU2132 - LQX的作业(概率论)
  14. 网络初始化失败,点击确定后将退出
  15. 莫纳什大学计算机专业在哪个校区,莫纳什大学校区几个
  16. ios 扫码枪外设 键盘模式_想把 iPad 当笔记本电脑用?可以试试这款外接键盘
  17. Jmeter对Web Socket进行压力测试 —— 200人直播课实战经验
  18. 秋天来了,穿衣搭配。简单几件穿出独特气质
  19. 快速开发EasyUI Datagrid报表 thinkphp框架 ppt和视频教程
  20. Java生成骑缝章带有CA电子签名认证

热门文章

  1. Gitlab服务器 forbidden
  2. 命令查看yarn当前任务列表
  3. Python中函数的括号
  4. 关于用transmac黑苹果制作引导盘无法识别
  5. 数字逻辑电路——反演规则与对偶规则
  6. 小程序canvas画入圆形图片
  7. 随便举个例子,说明单线程比多线程编程提高性能
  8. iMac一体机安装苹果和Win7双系统
  9. tree是不是动词_tree是什么意思!
  10. C语言 一步步教你做一个带有图形界面的冒险小游戏