目录
[PHP源码阅读]explode和implode函数,explodeimplode
explode
$limit
$delimiter
核心源码
php_explode
php_explode_negative_limit
implode
核心代码
php_implode
smart_str_appendl
 
首页 php教程 php手册 [PHP源码阅读]explode和implode函数,explodeimplode

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

Jun 13, 2016 am 08:39 AM
explode

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

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

explode

<p>array explode ( string $delimiter, string $string, [ , $limit ] )</p>
登录后复制

返回由字符串组成的数组,每个元素都是string的一个子串,被字符串$delimiter作为边界点分割出来。

$limit

如果设置了$limit,且为正数,则返回的数组最多包含$limit个元素,最后的那个元素将包含$string的剩余部分。

如果$limit是负数,则返回除了最后的-$limit个元素外的所有元素。

如果$limit是0,则会被当做1。

$delimiter

如果$delimiter为空,则函数返回FALSE。如果delimiter不在string中,且$limit为负数,则返回空数组。

核心源码

    <span>//</span><span> 如果delimiter为空字符串,返回FALSE</span>
    <span>if</span> (delim_len == <span>0</span><span>) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Empty delimiter</span><span>"</span><span>);
        RETURN_FALSE;
    }

    </span><span>//</span><span> 初始化返回的数组</span>
<span>    array_init(return_value);

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

    </span><span>//</span><span> 初始化zstr和zdelim的字符串变量</span>
    ZVAL_STRINGL(&zstr, str, str_len, <span>0</span><span>);
    ZVAL_STRINGL(</span>&zdelim, delim, delim_len, <span>0</span><span>);
    </span><span>if</span> (limit > <span>1</span><span>) {
        </span><span>//</span><span> limit大于1,limit默认是LONG_MAX</span>
        php_explode(&zdelim, &<span>zstr, return_value, limit);
    } </span><span>else</span> <span>if</span> (limit < <span>0</span><span>) {
        </span><span>//</span><span> limit 为负数</span>
        php_explode_negative_limit(&zdelim, &<span>zstr, return_value, limit);
    } </span><span>else</span><span> {
        </span><span>//</span><span> limit为0,被当作1处理,返回整个字符串,add_index_stringl函数将str追加到数组return_value中</span>
        add_index_stringl(return_value, <span>0</span>, str, str_len, <span>1</span><span>);
    }</span>
登录后复制

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

php_explode

<span>  endp </span>= Z_STRVAL_P(str) +<span> Z_STRLEN_P(str);

    </span><span>//</span><span> p1指向字符串的开始</span>
    p1 =<span> Z_STRVAL_P(str);
    </span><span>//</span><span> p2指向第一个分隔符的位置 ,找出分隔符位置主要用的是php_memnstr函数</span>
    p2 =<span> php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);

    </span><span>if</span> (p2 ==<span> NULL) {
        </span><span>//</span><span> p2为NULL表示找不到分隔符,直接返回整个字符串</span>
        add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), <span>1</span><span>);
    } </span><span>else</span><span> {
        </span><span>do</span><span> {
            </span><span>//</span><span> 将p1添加到return_value数组中 ,移动到下一个分隔符的位置</span>
            add_next_index_stringl(return_value, p1, p2 - p1, <span>1</span><span>);
            p1 </span>= p2 +<span> Z_STRLEN_P(delim);
        } </span><span>while</span> ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
                 --limit > <span>1</span><span>);

        </span><span>//</span><span> 将最后一个值追加到return_value</span>
        <span>if</span> (p1 <=<span> endp)
            add_next_index_stringl(return_value, p1, endp</span>-p1, <span>1</span><span>);
    }</span>
登录后复制

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

ZEND_API <span>int</span> add_next_index_stringl(zval *arg, <span>const</span> <span>char</span> *str, <span>uint</span> length, <span>int</span><span> duplicate) 
{
    zval </span>*<span>tmp;

    MAKE_STD_ZVAL(tmp);
    ZVAL_STRINGL(tmp, str, length, duplicate);

    </span><span>return</span> zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp, <span>sizeof</span>(zval *<span>), NULL);
}</span>
登录后复制

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

php_explode_negative_limit

<span>  //</span><span> 如果delimiter不在string中,且limit为负数,什么都不做,返回空的array,p2为NULL表示delimiter不在string中</span>
    <span>if</span> (p2 ==<span> NULL) {
        </span><span>/*<br />     如果limit <= -1,那么什么都不做,因此如果只有一个字符串,那么- 1 + (limit) <= 0<br />     返回空数组</span><span>*/</span><span>
    } </span><span>else</span><span> {
        </span><span>int</span> allocated = EXPLODE_ALLOC_STEP, found = <span>0</span><span>;
        </span><span>long</span><span> i, to_return;
        </span><span>char</span> **positions = emalloc(allocated * <span>sizeof</span>(<span>char</span> *<span>));
        </span><span>//</span><span> 第一个单词的位置</span>
        positions[found++] =<span> p1;
        </span><span>do</span><span> {
            </span><span>if</span> (found >=<span> allocated) {
                allocated </span>= found + EXPLODE_ALLOC_STEP;<span>/*</span><span> 保证有足够的内存空间 </span><span>*/</span><span>
                positions </span>= erealloc(positions, allocated*<span>sizeof</span>(<span>char</span> *<span>));
            }
            </span><span>//</span><span> positions保存每个单词的起始位置</span>
            positions[found++] = p1 = p2 +<span> Z_STRLEN_P(delim);
        } </span><span>while</span> ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) !=<span> NULL);

        </span><span>//</span><span> to_return 是return_value的数量,其实等于found - |limit|</span>
        to_return = limit +<span> found;
        </span><span>/*</span><span> limit至少是-1,因此不需要边界检查:i永远小于found </span><span>*/</span>
        <span>for</span> (i = <span>0</span>;i < to_return;i++) { <span>/*</span><span> 这个检查是检查to_return大于0 </span><span>*/</span><span>
            add_next_index_stringl(return_value, positions[i],
                    (positions[i</span>+<span>1</span>] - Z_STRLEN_P(delim)) -<span> positions[i],
                    </span><span>1</span><span>
                );
        }
        efree(positions);
    }</span>
登录后复制

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

implode

<p>string implode ( string $glue, array $pieces )</p>
<p>string implode ( array $pieces )</p>
登录后复制

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

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

核心代码

<span>if</span> (arg2 ==<span> NULL) {
        </span><span>//</span><span> 第二个参数为空,第一个参数必须为数组</span>
        <span>if</span> (Z_TYPE_PP(arg1) !=<span> IS_ARRAY) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Argument must be an array</span><span>"</span><span>);
            </span><span>return</span><span>;
        }

        MAKE_STD_ZVAL(delim);
</span><span>#define</span> _IMPL_EMPTY ""
        <span>//</span><span> 默认使用""连接</span>
        ZVAL_STRINGL(delim, _IMPL_EMPTY, <span>sizeof</span>(_IMPL_EMPTY) - <span>1</span>, <span>0</span><span>);

        SEPARATE_ZVAL(arg1);
        arr </span>= *<span>arg1;
    } </span><span>else</span><span> {
        </span><span>//</span><span> 根据参数类型设置参数的值</span>
        <span>if</span> (Z_TYPE_PP(arg1) ==<span> IS_ARRAY) {
            arr </span>= *<span>arg1;
            convert_to_string_ex(arg2);
            delim </span>= *<span>arg2;
        } </span><span>else</span> <span>if</span> (Z_TYPE_PP(arg2) ==<span> IS_ARRAY) {
            arr </span>= *<span>arg2;
            convert_to_string_ex(arg1);
            delim </span>= *<span>arg1;
        } </span><span>else</span><span> {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Invalid arguments passed</span><span>"</span><span>);
            </span><span>return</span><span>;
        }
    }

    </span><span>//</span><span> 调用php_implode函数进行转换</span>
    php_implode(delim, arr, return_value TSRMLS_CC);
登录后复制

在底层实现中,implode函数处理好参数之后就调用php_implode函数进行转换。

php_implode

<span>  //</span><span> 遍历数组的每一个元素,判断其类型,然后调用smart_str_appendl函数将值追加到字符串中</span>
    <span>while</span> (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (<span>void</span> **) &tmp, &pos) ==<span> SUCCESS) {
        </span><span>switch</span> ((*tmp)-><span>type) {
            </span><span>case</span><span> IS_STRING:
                smart_str_appendl(</span>&<span>implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
                </span><span>break</span><span>;

            </span><span>case</span><span> IS_LONG: {
                </span><span>char</span> stmp[MAX_LENGTH_OF_LONG + <span>1</span><span>];
                str_len </span>= slprintf(stmp, <span>sizeof</span>(stmp), <span>"</span><span>%ld</span><span>"</span><span>, Z_LVAL_PP(tmp));
                smart_str_appendl(</span>&<span>implstr, stmp, str_len);
            }
                </span><span>break</span><span>;

            </span><span>case</span><span> IS_BOOL:
                </span><span>if</span> (Z_LVAL_PP(tmp) == <span>1</span><span>) {
                    smart_str_appendl(</span>&implstr, <span>"</span><span>1</span><span>"</span>, <span>sizeof</span>(<span>"</span><span>1</span><span>"</span>)-<span>1</span><span>);
                }
                </span><span>break</span><span>;

            </span><span>case</span><span> IS_NULL:
                </span><span>break</span><span>;

            </span><span>case</span><span> IS_DOUBLE: {
                </span><span>char</span> *<span>stmp;
                str_len </span>= spprintf(&stmp, <span>0</span>, <span>"</span><span>%.*G</span><span>"</span>, (<span>int</span><span>) EG(precision), Z_DVAL_PP(tmp));
                smart_str_appendl(</span>&<span>implstr, stmp, str_len);
                efree(stmp);
            }
                </span><span>break</span><span>;

            </span><span>case</span><span> IS_OBJECT: {
                </span><span>int</span><span> copy;
                zval expr;
                zend_make_printable_zval(</span>*tmp, &expr, &<span>copy);
                smart_str_appendl(</span>&<span>implstr, Z_STRVAL(expr), Z_STRLEN(expr));
                </span><span>if</span><span> (copy) {
                    zval_dtor(</span>&<span>expr);
                }
            }
                </span><span>break</span><span>;

            </span><span>default</span><span>:
                tmp_val </span>= **<span>tmp;
                zval_copy_ctor(</span>&<span>tmp_val);
                convert_to_string(</span>&<span>tmp_val);
                smart_str_appendl(</span>&<span>implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
                zval_dtor(</span>&<span>tmp_val);
                </span><span>break</span><span>;

        }

        </span><span>//</span><span> 添加glue字符</span>
        <span>if</span> (++i !=<span> numelems) {
            smart_str_appendl(</span>&<span>implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
        }
        zend_hash_move_forward_ex(Z_ARRVAL_P(arr), </span>&<span>pos);
    }
    </span><span>//</span><span> 在尾部添加字符0</span>
    smart_str_0(&implstr);
登录后复制

可以看到,php_implode函数遍历数组的每一个元素,判断其类型,并进行必要的类型转换,然后调用smart_str_appendl函数将值追加到字符串中。smart_str_appendl是implode实现代码中的核心函数。

smart_str_appendl

<span>#define</span> smart_str_appendl(dest, src, len) \<span>
    smart_str_appendl_ex((dest), (src), (len), </span><span>0</span><span>)

</span><span>#define</span> smart_str_appendl_ex(dest, src, nlen, what) do {            \<span>
    register size_t __nl;                                            \
    smart_str </span>*__dest = (smart_str *<span>) (dest);                        \
                                                                    \
    smart_str_alloc4(__dest, (nlen), (what), __nl);                    \
    memcpy(__dest</span>->c + __dest-><span>len, (src), (nlen));                    \
    __dest</span>->len =<span> __nl;                                                \
} </span><span>while</span> (<span>0</span>)
登录后复制

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

 

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

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

 

 

更多PHP源码阅读文章:

[PHP源码阅读]strlen函数

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

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系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.能量晶体解释及其做什么(黄色晶体)
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前 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 explode函数使用方法与报错解决 PHP explode函数使用方法与报错解决 Mar 10, 2024 am 09:18 AM

PHP中的explode函数是一种用来将字符串分割成数组的函数,它非常常用且灵活。在使用explode函数的过程中,常常会遇到一些报错和问题,本文将介绍explode函数的基本用法并提供一些解决报错的方法。一、explode函数基本用法在PHP中,explode函数的基本语法如下:explode(string$separator,string$stri

PHP中使用explode函数时常见的错误及解决方案 PHP中使用explode函数时常见的错误及解决方案 Mar 11, 2024 am 08:33 AM

标题:PHP中使用explode函数时常见的错误及解决方案在PHP中,explode函数是用于将字符串分割成数组的常用函数。然而,由于使用不当或者数据格式不正确,可能会导致一些常见的错误。本文将针对在使用explode函数时可能遇到的问题进行分析,并提供解决方案和具体的代码示例。错误一:未传入分隔符参数在使用explode函数时,最常见的错误之一是未传入分隔

使用explode和implode函数分割和合并字符串 使用explode和implode函数分割和合并字符串 Jun 15, 2023 pm 08:42 PM

在PHP编程中,处理字符串是一个经常需要进行的操作。其中,分割和合并字符串则是两种常见的需求。为了更方便地进行这些操作,PHP提供了两个非常实用的函数,即explode和implode函数。本文将介绍这两个函数的用法,以及一些实用的技巧。一、explode函数explode函数用于将一个字符串按照指定的分隔符进行分割,并返回一个数组。其函数原型如下:arra

php explode报错怎么办 php explode报错怎么办 Jan 18, 2023 am 10:13 AM

php explode报错的解决办法:1、找到并打开出错的PHP代码;2、找到explode函数部分;3、修改代码为“dump(explode(',',$str));die;”,也就是用逗号分割为数组即可。

使用PHP函数 'explode' 将字符串拆分为数组 使用PHP函数 'explode' 将字符串拆分为数组 Jul 24, 2023 pm 11:09 PM

使用PHP函数"explode"将字符串拆分为数组在PHP开发中,经常会遇到需要将一个字符串按照指定的分隔符进行拆分的情况。这时,我们可以使用PHP内置函数"explode"来实现字符串到数组的转换。本文将介绍如何使用"explode"函数来拆分字符串,并给出相关的代码示例。"explode"函数的基本语法如下:arrayexplode(

使用PHP函数 'explode' 将字符串拆分为多个子字符串 使用PHP函数 'explode' 将字符串拆分为多个子字符串 Jul 25, 2023 pm 06:29 PM

使用PHP函数"explode"将字符串拆分为多个子字符串在PHP编程中,我们经常会遇到需要将一个字符串拆分为多个子字符串的情况。这时,PHP提供了一个非常方便的函数"explode",可以帮助我们轻松实现这个功能。"explode"函数的语法如下:arrayexplode(string$delimiter,string$string[,in

PHP中如何使用explode函数分割字符串 PHP中如何使用explode函数分割字符串 Jun 26, 2023 pm 12:03 PM

在PHP语言中,有很多基础函数可以帮我们快速有效地处理字符串。其中,explode函数是一个很实用的字符串分割函数。它可以将一个字符串按照指定的分割符分割成数组,进而进行更为灵活的字符串操作。在本文中,我们将会介绍PHP中如何使用explode函数来分割字符串。一、explode函数格式explode函数在PHP语言中的格式如下:explode(separa

explode()函数在PHP中是什么? explode()函数在PHP中是什么? Sep 04, 2023 pm 01:01 PM

在本文中,了解如何使用PHPExplode()函数,该函数是预定义的内置PHP函数。explode函数用于“将字符串拆分为PHP中的explode函数使我们能够通过break将一个字符串分解成更小的内容。这种分隔符称为分隔符。语法explode(分隔符,字符串,元素数)参数爆炸函数接受三个参数,其中两个是强制的,一个是可选的。让我们讨论这三个参数。分隔符这个字符指定临界点或点字符串将在此处分割,即每当在字符串中找到该字符时,它就象征着数组中一个元素的结束和另一个元素的开始。String输入字符串

See all articles