【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為負數,則返回空數組。
運行樣本
$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函數,下面是該函數的執行流程圖:
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函數的執行流程圖如下:
// 遍曆數組的每一個元素,判斷其類型,然後調用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函數將值追加到返回的字串後面。最後,還要在字串後面加上結束符,這是個必須的操作,以後編程時也應注意。
smart_str_appendl是函數smart_str_appendl_ex的宏定義,該函數調用了memcpy做字串的複製。
小結
原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。
暫且寫這麼多吧,還有更多的最佳化和PHP源碼中常用的函數,將會在以後的源碼閱讀中慢慢講述。
如果本文對你有協助,請點下推薦吧,謝謝^_^
最後,我在github有對PHP源碼更詳細的註解。感興趣的可以圍觀一下,給個star。PHP5.4源碼註解。
http://www.bkjia.com/PHPjc/1128118.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/1128118.htmlTechArticle【PHP源碼閱讀】explode和implode函數,explodeimplode explode和implode函數主要用作字串和數組間轉換的操作,比如擷取一段參數後根據某個字元分...