亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

[PHP源碼閱讀]explode和implode函數

2020-03-22 20:27:56
字體:
來源:轉載
供稿:網友
  • 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_html' target='_blank'>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, int duplicate) {    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;        long i, 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) {            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, &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函數進行字符串復制。

    原創文章 http://www.cnblogs.com/h-hq/p/5509090.html

    PHP編程

    鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
    国内偷自视频区视频综合| 国产精品91在线| 国产视频999| 一区二区日韩精品| 欧美激情在线视频二区| 中文字幕亚洲欧美日韩在线不卡| 久久久久日韩精品久久久男男| 亚洲xxxx3d| 欧美野外wwwxxx| 成人自拍性视频| 2019亚洲日韩新视频| 亚洲国产另类久久精品| 久久99久久亚洲国产| 日韩在线观看成人| 中文字幕亚洲一区在线观看| 欧美日韩一区二区免费视频| 亚洲视频在线观看| 欧美激情精品久久久久久黑人| 国产精品稀缺呦系列在线| 亚洲第一福利网站| 亚洲自拍偷拍色图| 超薄丝袜一区二区| 国产精品一区二区三区久久久| 91精品久久久久久久久久| 国产精品三级久久久久久电影| 亚洲老司机av| 色综合天天狠天天透天天伊人| 高清视频欧美一级| 亚洲精品免费在线视频| 亚洲黄在线观看| 高潮白浆女日韩av免费看| 国产精品嫩草影院一区二区| 日韩精品中文字幕在线观看| 久久中文字幕国产| 亚洲天堂av图片| 国产亚洲视频中文字幕视频| 亚洲欧美中文日韩在线| 麻豆乱码国产一区二区三区| 国产日韩欧美视频| 日韩国产精品亚洲а∨天堂免| 日韩麻豆第一页| 欧美高清自拍一区| 美日韩精品免费观看视频| 啪一啪鲁一鲁2019在线视频| 欧美在线观看视频| 日韩电影中文字幕一区| 国产一区二区三区在线| xvideos亚洲| 91精品久久久久| 88国产精品欧美一区二区三区| 欧美色另类天堂2015| 国产欧美欧洲在线观看| 91精品在线看| 亚洲欧美日韩中文在线制服| 亚洲欧美综合区自拍另类| 亚洲天堂第二页| 日韩av影片在线观看| 欧美日韩免费看| 久久久久久久爱| 亚洲三级av在线| 日韩av三级在线观看| 亚洲性生活视频| 日韩电影免费在线观看中文字幕| 久久久女女女女999久久| 538国产精品一区二区在线| 成人国内精品久久久久一区| 国产成人精品日本亚洲专区61| 欧美高清自拍一区| 欧美国产亚洲精品久久久8v| 国产日韩在线观看av| 欧美黄色成人网| 久久精品久久精品亚洲人| 国产精品亚洲一区二区三区| 国产男人精品视频| 91精品久久久久久久久久入口| 欧美激情啊啊啊| 福利一区福利二区微拍刺激| 青草热久免费精品视频| 日韩高清不卡av| 久久亚洲精品毛片| 欧美日韩成人免费| 亚洲曰本av电影| 亚洲电影免费在线观看| 久久精品99国产精品酒店日本| 国产一区二区三区在线视频| 国产精品嫩草视频| 高潮白浆女日韩av免费看| 91综合免费在线| 国产精品第2页| 国产精品久久久久9999| 97国产真实伦对白精彩视频8| 欧美在线日韩在线| 亚洲第一精品夜夜躁人人躁| 欧美激情xxxxx| 2019亚洲日韩新视频| 国产成人精品在线播放| 亚洲一区二区三区四区在线播放| 曰本色欧美视频在线| 日韩美女视频中文字幕| 国产91网红主播在线观看| 欧美中文在线字幕| 久久综合国产精品台湾中文娱乐网| 欧美巨猛xxxx猛交黑人97人| 国产精品免费电影| 国产精品一区二区久久精品| 精品国产一区二区三区久久| 欧美成人午夜激情视频| 国产成人精品在线播放| 亚洲成色777777在线观看影院| 国产精品第七影院| 亚洲国产精品人久久电影| 97久久精品在线| 国产一区二区三区在线播放免费观看| 国产精品极品尤物在线观看| 日韩精品免费在线视频| 久久精品国产亚洲7777| 欧美性在线观看| 91精品国产高清久久久久久91| 中文字幕日韩有码| 精品视频在线播放色网色视频| 国产这里只有精品| 最新国产成人av网站网址麻豆| 国产精品稀缺呦系列在线| 伊人激情综合网| 久久中文久久字幕| 欧美一级视频一区二区| 最近2019年日本中文免费字幕| 亚洲最大激情中文字幕| 国产精品成人国产乱一区| 国产精品欧美一区二区| 欧美性感美女h网站在线观看免费| 亚洲视频电影图片偷拍一区| 亚洲日本中文字幕| 毛片精品免费在线观看| 久久精品国产一区二区三区| 日韩欧美在线播放| 欧美日韩xxx| 国产精品偷伦免费视频观看的| 97在线免费观看| 国产成人综合精品在线| 91亚洲精品一区| 久久精视频免费在线久久完整在线看| 日韩人在线观看| 中文字幕无线精品亚洲乱码一区| 亚洲国产天堂久久国产91| 日本精品久久久久久久| 2019中文字幕免费视频| 亚洲伊人久久大香线蕉av| 日韩在线播放av| 全球成人中文在线| 一区二区三区视频免费| 亚洲电影免费观看高清完整版| 国产九九精品视频| 在线观看精品自拍私拍| 久久亚洲精品毛片| 日韩激情av在线播放| 中文字幕国产日韩| 国产香蕉一区二区三区在线视频| 77777亚洲午夜久久多人| 亚洲曰本av电影| 久久久久久久久亚洲| 亚洲男女自偷自拍图片另类| 91精品免费久久久久久久久| 97久久精品视频|