大家都知道这两个函数都是截取字符串的,一个是可以按字节截取,另外一个是可以按字截取
我写了一个例子:for($i = 0;$i< 100000; $i ++){
$a = substr($str, 0, 1);
}和for($i = 0;$i< 100000; $i ++){
$a = mb_substr($str, 0, 1);
}两个的执行时间在我的电脑显示
执行程序共耗费 0.097547054290771秒
执行程序共耗费 0.10249900817871秒但是如果我吧mb_substr 加上encode参数,for($i = 0;$i< 100000; $i ++){
$a = mb_substr($str, 0, 1, "gbk"); // 或utf-8
}则差别太大了
执行程序共耗费 0.097554922103882秒
执行程序共耗费 4.9396300315857秒为什么加上encode之后,mb_substr的执行效率会降这么多呢?

解决方案 »

  1.   

      
        string.no_encoding = MBSTRG(current_internal_encoding);   //默认为当前内部编码    argc = ZEND_NUM_ARGS();   
        switch (argc) {           
        case 2:
            if (zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) {
                WRONG_PARAM_COUNT;
            }
            break;
        case 3:
            if (zend_get_parameters_ex(3, &arg1, &arg2, &arg3) == FAILURE) {
                WRONG_PARAM_COUNT;
            }
            break;
        case 4:
            if (zend_get_parameters_ex(4, &arg1, &arg2, &arg3, &arg4) == FAILURE) {
                WRONG_PARAM_COUNT;
            }
            convert_to_string_ex(arg4);    
            string.no_encoding = mbfl_name2no_encoding(Z_STRVAL_PP(arg4));
            if (string.no_encoding == mbfl_no_encoding_invalid) { 
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown encoding \"%s\"", Z_STRVAL_PP(arg4));
                RETURN_FALSE;     
            }
            break;                
        default:
            WRONG_PARAM_COUNT;
        }
       
    }enum mbfl_no_encoding
    mbfl_name2no_encoding(const char *name)
    {
        const mbfl_encoding *encoding;    encoding = mbfl_name2encoding(name);
        if (encoding == NULL) {
            return mbfl_no_encoding_invalid;
        } else {
            return encoding->no_encoding;
        }   
    }const mbfl_encoding *
    mbfl_name2encoding(const char *name)
    {
        const mbfl_encoding *encoding;
        int i, j;    if (name == NULL) {
            return NULL;
        }    i = 0;
        while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL){
            if (strcasecmp(encoding->name, name) == 0) {
                return encoding;
            }
        }    /* serch MIME charset name */
        i = 0;
        while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL) {
            if (encoding->mime_name != NULL) {
                if (strcasecmp(encoding->mime_name, name) == 0) {
                    return encoding;
                }
            }
        }    /* serch aliases */
        i = 0;
        while ((encoding = mbfl_encoding_ptr_list[i++]) != NULL) {
            if (encoding->aliases != NULL) {
                j = 0;
                while ((*encoding->aliases)[j] != NULL) {
                    if (strcasecmp((*encoding->aliases)[j], name) == 0) {
                        return encoding;
                    }
                    j++;
                }
            }
        }    return NULL;
    }
    可以看到,如果提供了第四个参数,php会解析这个参数
    1. 将这个参数转换成字符串.
    2. 调用mbfl_name2no_encoding获得编码器序号
    3. 第二步会调用mbfl_name2encoding,这个函数在循环中使用了strcasecmpstrcasecmp是忽略大小写的字符串匹配,性能很低,
    而且,如果第四个参数提供的 编码名字 不规范,会造成标准名字列表中找不到
    还会做进一步的尝试,从MIME charset name中寻找,如果还是找不到
    会继续尝试,通过别名来查找,这个过程是相当慢的,假如有20种编码,每种有10个别名
    就要从20*10个字符串中,查找出匹配的,还是不区分大小写的匹配,相当的慢所以,尽量使用跟内部编码一致的编码,如果不能,编码名字一定要写的规范
      

  2.   

    这很简单!
    加了encode之后,mb_substr需要逐字判别字边界。
    虽然慢了,但准确度高了
      

  3.   

    如果很在乎性能,可以写一个php扩展,实现更高效的mb_substr
    扩展中把最近使用的10个编码名字,放到在zend_hash_table中
    这样就不需要每次都查找那么多次
      

  4.   

    加了编码,mb_str就多做了判断编码的工作,所以慢了,但结果更准确了!
      

  5.   

    或者使用mb_internal_encoding设置一个默认的encoding也可以
      

  6.   

    你可以试试
    改成这个样子mb_internal_encoding("gbk");
    for($i = 0; $i < 100000; $i ++){
        $a = mb_substr($str, 0, 1); 

      

  7.   

    -------------------------------
    substr只用于英文, mb_substr用于各种不同编码的文字符号, 甚至乱码也OK, 速度慢, 也就是6楼说的情况
    -------------------------------
    mb_substr($str, 0, 1, "gbk"); //传参时间 + 函数内部判断参数, 现在多了一个参数, 运行时间倍加是必然
      

  8.   


    其实不是因为多字节的缘故,
    而是编码名字的查找,耗费了大量时间//写法一,在我这里耗费3.4秒
    <?php
    $str = "abc我";
    for ($i=0; $i<1000000; $i++)
        $a = mb_substr($str, 0, 2, "utf8");
    ?>
    //
    //
    //写法二,在我这里耗费1.4秒
    <?php
    $str = "abc我";
    for ($i=0; $i<1000000; $i++)
        $a = mb_substr($str, 0, 2, "UTF-8");
    ?>
    //
    //
    //写法三,在我这里耗费0.7秒
    <?php
    $str = "abc我";
    mb_internal_encoding("UTF-8");
    for ($i=0; $i<1000000; $i++)
        $a = mb_substr($str, 0, 2);
    ?>
    //
    //
    //
    //减去解释器载入和初始化以及代码编译的时间
    //各个方案的性能差别,就更大了
      

  9.   

    你可以来看看偶滴帖子http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20091109%2F17%2F655bdffd-3187-483e-a821-c5b68582de10.html