PHP內置函數分析之strlen 與 mb_strlen

 在PHP裏 有兩個計算 字符串個數的函數php

一個是 strlen,一個是mb_strlen;
先來看看幫助手冊的定義ide

  • strlen

strlen — 獲取字符串長度
int strlen ( string $string )
返回給定的字符串 string 的長度。函數

  • mb_strlen

int mb_strlen ( string $str [, string $encoding ] )ui

返回給定的字符串 string 的長度。編碼

encoding參數爲字符編碼。若是省略,則使用內部字符編碼。spa

 這麼看 除了mb_strlen能夠傳遞一個 字符編碼好像沒有其餘區別

寫一個PHP程序來看看字符串

 

  
  
  
  
  1. $a="我是s斯t人"
  2. echo strlen($a); 
  3. echo "<br>"
  4. echo mb_strlen($a,'utf8'); 

 

輸出結果
14
6
很明顯 strlen對於中文來說,每一個漢字佔三個字節,$a的字節數就是14,說明 strlen計算的是字符串所佔的字節數
在mb_strlen計算時,若是encoding設置爲utf8,那麼,中文將佔一個字節 那麼$a就是6get

須要注意的是 mb_strlen並非PHP內置函數,須要修改php.ini,開啓 php_mbstring
好了..
咱們下面就深刻到PHP內核源碼去看看兩個函數的不一樣.
先看mb_strlen的定義源碼

  
  
  
  
  1. PHP_FUNCTION(mb_strlen) 
  2.         int n; 
  3.         mbfl_string string; 
  4.         char *enc_name = NULL;        int enc_name_len; 
  5.   
  6.         mbfl_string_init(&string); 
  7.         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) { 
  8.                 RETURN_FALSE; 
  9.         }     
  10.   
  11.         string.no_language = MBSTRG(language); 
  12.         if (enc_name == NULL) {                string.no_encoding = MBSTRG(current_internal_encoding); 
  13.         } else { 
  14.                 string.no_encoding = mbfl_name2no_encoding(enc_name); 
  15.                 if (string.no_encoding == mbfl_no_encoding_invalid) { 
  16.                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name);                        RETURN_FALSE; 
  17.                 } 
  18.         }             
  19.   
  20.         n = mbfl_strlen(&string); 
  21.         if (n >= 0) { 
  22.                 RETVAL_LONG(n); 
  23.         } else { 
  24.                 RETVAL_FALSE; 
  25.         } 

 

mbfl_string 是一個結構體string

 

  
  
  
  
  1. typedef struct _mbfl_string { 
  2.         enum mbfl_no_language no_language; 
  3.         enum mbfl_no_encoding no_encoding; 
  4.         unsigned char *val;        unsigned int len; 
  5. } mbfl_string; 

看定義就知道,這兩個保存了當前字符串的語言,編碼,保存的值和長度
mbfl_string_init(&string);
這個函數是初始化string;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 「s|s」, (char **)&string.val, &string.len, &enc_name, &enc_name_len) == FAILURE) {
RETURN_FALSE;
}
這裏接收傳遞過來的兩個參數,也就是前面看到的 string和encoding,
enc_name保存編碼,enc_name_len保存編碼名字的長度
string.no_language = MBSTRG(language);
展開後
#define MBSTRG(v) (mbstring_globals.v)
這裏將mbstring的language賦給string的no_language;

 

  
  
  
  
  1. if (enc_name == NULL) {//若是沒有手動設置編碼,那麼就使用PHP內置的編碼 這個時候就與strlen相同 
  2.          string.no_encoding = MBSTRG(current_internal_encoding); 
  3.  }else { 
  4.                //檢查是不是有效的編碼 
  5.                string.no_encoding = mbfl_name2no_encoding(enc_name); 
  6.                //若是傳遞來的編碼無效 拋出異常 
  7.                 if (string.no_encoding == mbfl_no_encoding_invalid) { 
  8.                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", enc_name); 
  9.                         RETURN_FALSE; 
  10.                 } 
  11.         } 
  12. n = mbfl_strlen(&string);//計算字符串的長度 

原來這個函數裏只是驗證編碼
真正計算長度的函數是mbfl_strlen

 

  
  
  
  
  1. int  mbfl_strlen(mbfl_string *string) 
  2.         int len, n, m, k; 
  3.         unsigned char *p; 
  4.         const unsigned char *mbtab; 
  5.         const mbfl_encoding *encoding; 
  6.        //驗證編碼是否有效 
  7.         encoding = mbfl_no2encoding(string->no_encoding); 
  8.         if (encoding == NULL || string == NULL) { 
  9.                 return -1; 
  10.         }  
  11.   
  12.         len = 0; 
  13. //下面是幾種不一樣的 
  14.         if (encoding->flag & MBFL_ENCTYPE_SBCS) {//是單字節字符集 直接返回 
  15.                 len = string->len; 
  16.         } else if (encoding->flag & (MBFL_ENCTYPE_WCS2BE | MBFL_ENCTYPE_WCS2LE)) { //寬字節每一個字佔2位 
  17.                 len = string->len/2; 
  18.         } else if (encoding->flag & (MBFL_ENCTYPE_WCS4BE | MBFL_ENCTYPE_WCS4LE)) {//寬字節每一個字佔4位 
  19.                 len = string->len/4; 
  20.         } else if (encoding->mblen_table != NULL) {   //mblen_table是作什麼的沒搞清楚,望賜教 
  21.                 mbtab = encoding->mblen_table; 
  22.                 n = 0; 
  23.                 p = string->val; 
  24.                 k = string->len; 
  25.                 /* count */ 
  26.                 if (p != NULL) { 
  27.                         while (n < k) { 
  28.                                 m = mbtab[*p]; 
  29.                                 n += m; 
  30.                                 p += m; 
  31.                                 len++; 
  32.                         }; 
  33.                 } 
  34.         } else { //其餘編碼 轉換成mbfl_no_encoding_wchar再計算 
  35.                 /* wchar filter */ 
  36.                 mbfl_convert_filter *filter = mbfl_convert_filter_new( 
  37.                   string->no_encoding, 
  38.                   mbfl_no_encoding_wchar, 
  39.                   filter_count_output, 0, &len); 
  40.                 if (filter == NULL) { 
  41.                         return -1; 
  42.                 } 
  43.                 /* count */ 
  44.                 n = string->len; 
  45.                 p = string->val; 
  46.                 if (p != NULL) { 
  47.                         while (n > 0) { 
  48.                                 (*filter->filter_function)(*p++, filter); 
  49.                                 n--; 
  50.                         } 
  51.                 } 
  52.                 mbfl_convert_filter_delete(filter); 
  53.         } 
  54.   
  55.         return len; 


mb_strlen就是根據encoding不一樣的編碼,來分別計算..好像能夠計算世界大部分不一樣的編碼格式
相比 mb_strlen ,strlen就簡單的多多的多的多了
開始 沒有找到 strlen定義的地方,
它在 Zend/zend_builtin_functions.c裏定義的

 

  
  
  
  
  1. ZEND_FUNCTION(strlen) 
  2.         char *s1; 
  3.         int s1_len; 
  4.   
  5.         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &s1, &s1_len) == FAILURE) { 
  6.                 return
  7.         }     
  8.   
  9.         RETVAL_LONG(s1_len); 

很簡單 只是獲取長度而已…

這下 他們倆的區別就很清楚了…

相關文章
相關標籤/搜索