程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 【PHP源碼閱讀】explode和implode函數,explodeimplode

【PHP源碼閱讀】explode和implode函數,explodeimplode

編輯:關於PHP編程

【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, &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是函數smart_str_appendl_ex的宏定義,該函數調用了memcpy做字符串的復制。

小結

原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

暫且寫這麼多吧,還有更多的優化和PHP源碼中常用的函數,將會在以後的源碼閱讀中慢慢講述。

如果本文對你有幫助,請點下推薦吧,謝謝^_^

 

最後,我在github有對PHP源碼更詳細的注解。感興趣的可以圍觀一下,給個star。PHP5.4源碼注解。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved