资讯专栏INFORMATION COLUMN

[PHP源码阅读]explode和implode函数

Ocean / 495人阅读

摘要:在实现里面,如果大于,则调用函数如果小于,则调用函数如果等于,则被当做处理,此时调用函数将添加到数组中。找到分隔符的位置之后,就调用函数将分隔得到的字符串插入到返回数组里。此函数可以看作是的逆向过程。调用函数做字符串的连接。

explode和implode函数主要用作字符串和数组间转换的操作,比如获取一段参数后根据某个字符分割字符串,或者将一个数组的结果使用一个字符合并成一个字符串输出。在PHP中经常会用到这两个函数,因此有必要了解一下其原理。

我在github有对PHP源码更详细的注解。感兴趣的可以围观一下,给个star。PHP5.4源码注解。可以通过commit记录查看已添加的注解。

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函数,下面是该函数的执行流程图:

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函数不会计算

如果不设置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函数的执行流程图如下:

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源码注解。可以通过commit记录查看已添加的注解。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/21586.html

相关文章

  • [PHP源码阅读]trim、rtrim、ltrim函数

    摘要:系列函数是用于去除字符串中首尾的空格或其他字符。此处要注意,左右两边是一对合法的范围值,如果传递的是非法的值会报错。本文主要对函数进行分析,和函数跟的类似。更多源码文章源码阅读函数性能为王从源码剖析和源码阅读和函数源码阅读和函数 trim系列函数是用于去除字符串中首尾的空格或其他字符。ltrim函数只去除掉字符串首部的字符,rtrim函数只去除字符串尾部的字符。 我在github有对P...

    时飞 评论0 收藏0
  • PHP之string之implode()函数使用

    摘要:将一个一维数组的值转化为字符串用将一维数组的值连接为一个字符串。因为历史原因,可以接收两种参数顺序,但是不行。不过按文档中的顺序可以避免混淆。默认为空的字符串。你想要转换的数组。返回一个字符串,其内容为由分割开的数组的值。 implode (PHP 4, PHP 5, PHP 7) implode — Join array elements with a string implode...

    2json 评论0 收藏0
  • PHP之string之explode()函数使用

    摘要:由于历史原因,虽然可以接收两种参数顺序,但是不行。此函数返回由字符串组成的,每个元素都是的一个子串,它们被字符串作为边界点分割出来。如果所包含的值在中找不到,并且使用了负数的,那么会返回空的,否则返回包含单个元素的数组。 explode (PHP 4, PHP 5, PHP 7) explode — Split a string by string explode — 使用一个字符串...

    wenzi 评论0 收藏0
  • Laravel 学习笔记之 Query Builder 源码解析(下)

    摘要:,看下源码返回很容易知道返回值是,然后将该值存储在变量中,这时。看下的源码去除掉字符后为返回从源码中可知道返回值为,这时。 说明:本文主要学习下Query Builder编译Fluent Api为SQL的细节和执行SQL的过程。实际上,上一篇聊到了IlluminateDatabaseQueryBuilder这个非常重要的类,这个类含有三个主要的武器:MySqlConnection, M...

    qpal 评论0 收藏0
  • Php常用函数系列之字符串处理

    摘要:规定要检查的字符串。遇到这种情况时可以使用函数进行检测。输出反引用一个引用字符串函数示例反引用一个引用字符串输出连接分割字符串使用一个字符串分割另一个字符串边界上的分隔字符。应使用运算符来测试返回值函数示例输出返回字符串的子串输入字符串。 转自我的github函数示例源码 字符串的格式化 rtrim(),除字符串右端的空白字符或其他预定义字符 ltrim(),删除字符串开头空格或...

    陆斌 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<