目錄
[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