PHP源码之implode函数源码怎么用

发布时间:2020-11-16 11:03:33 作者:小新
来源:亿速云 阅读:144

这篇文章将为大家详细讲解有关PHP源码之implode函数源码怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

PHP 中的 implode

// 方法1
implode ( string $glue , array $pieces ) : string
// 方法2
implode ( array $pieces ) : string
$pieces = [
    123,
    ',是一个',
    'number!',
];
$str1 = implode($pieces);
$str2 = implode('', $pieces);

var_dump($str1, $str2);
/*
string(20) "123,是一个number!"
string(20) "123,是一个number!"
*/

implode 源码实现

if (arg2 == NULL) {
    if (Z_TYPE_P(arg1) != IS_ARRAY) {
        php_error_docref(NULL, E_WARNING, "Argument must be an array");
        return;
    }

    glue = ZSTR_EMPTY_ALLOC();
    tmp_glue = NULL;
    pieces = arg1;
} else {
    if (Z_TYPE_P(arg1) == IS_ARRAY) {
        glue = zval_get_tmp_string(arg2, &tmp_glue);
        pieces = arg1;
    } else if (Z_TYPE_P(arg2) == IS_ARRAY) {
        glue = zval_get_tmp_string(arg1, &tmp_glue);
        pieces = arg2;
    } else {
        php_error_docref(NULL, E_WARNING, "Invalid arguments passed");
        return;
    }
}

不传递 pieces 参数

十分关键的 php_implode

#define PHP_FUNCTION            ZEND_FUNCTION
// 对应的 ZEND_FUNCTION 定义如下
#define ZEND_FUNCTION(name)                ZEND_NAMED_FUNCTION(ZEND_FN(name))
// 对应的 ZEND_NAMED_FUNCTION 定义如下
#define ZEND_NAMED_FUNCTION(name)        void ZEND_FASTCALL name(INTERNAL_FUNCTION_PARAMETERS)
// 对应的 ZEND_FN 定义如下
#define ZEND_FN(name) zif_##name
// 对应的 ZEND_FASTCALL 定义如下
# define ZEND_FASTCALL __attribute__((fastcall))
void zif_implode(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC)
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zend_array), tmp) {
    // ...
} ZEND_HASH_FOREACH_END();
struct {
    zend_string *str;
    zend_long    lval;
} *strings, *ptr;
字符串
// tmp 是循环中的单元值
ptr->str = Z_STR_P(tmp);
len += ZSTR_LEN(ptr->str);
ptr->lval = 0;
ptr++;
整数类型
while (val) {
    val /= 10;
    len++;
}
if (val <= 0) {
    len++;
}

字符串的处理和拷贝

cptr -= ZSTR_LEN(ptr->str);
memcpy(cptr, ZSTR_VAL(ptr->str), ZSTR_LEN(ptr->str));
free_alloca(strings, use_heap);
RETURN_NEW_STR(str);

实践

static void su_php_implode(const zend_string *glue, zval *pieces, zval *return_value)
{
    // 源码内容省略
}
PHP_FUNCTION(su_test)
{
    zval tmp;
    zend_string *str, *glue, *tmp_glue;
    zval *arg1, *arg2 = NULL, *pieces;

    ZEND_PARSE_PARAMETERS_START(1, 2)
        Z_PARAM_ZVAL(arg1)
        Z_PARAM_OPTIONAL
        Z_PARAM_ZVAL(arg2)
    ZEND_PARSE_PARAMETERS_END();
    glue = zval_get_tmp_string(arg1, &tmp_glue);
    pieces = arg2;
    su_php_implode(glue, pieces, return_value);
}
// t1.php
$res = su_test('-', [
    2019, '01', '01',
]);
var_dump($res);
gdb php
b zval_get_tmp_string
r t1.php
Breakpoint 1, zif_su_test (execute_data=0x7ffff1a1d0c0, 
    return_value=0x7ffff1a1d090)
    at /home/www/clang/php-7.3.3/ext/su_dd/su_dd.c:179
179        glue = zval_get_tmp_string(arg1, &tmp_glue);
184        su_php_implode(glue, pieces, return_value);
$1 = (zval *) 0x7ffff1a1d120
(gdb) p *$1
$2 = {value = {lval = 140737247576960, dval = 6.9533439118030153e-310, 
    counted = 0x7ffff1a60380, str = 0x7ffff1a60380, arr = 0x7ffff1a60380, 
    obj = 0x7ffff1a60380, res = 0x7ffff1a60380, ref = 0x7ffff1a60380, 
    ast = 0x7ffff1a60380, zv = 0x7ffff1a60380, ptr = 0x7ffff1a60380, 
    ce = 0x7ffff1a60380, func = 0x7ffff1a60380, ww = {w1 = 4054188928, 
      w2 = 32767}}, u1 = {v = {type = 7 '\a', type_flags = 1 '\001', u = {
        call_info = 0, extra = 0}}, type_info = 263}, u2 = {next = 0, 
    cache_slot = 0, opline_num = 0, lineno = 0, num_args = 0, fe_pos = 0, 
    fe_iter_idx = 0, access_flags = 0, property_guard = 0, constant_flags = 0, 
    extra = 0}}
struct _zval_struct {
    zend_value        value;            /* value */
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    type,            /* active type */
                zend_uchar    type_flags,
                union {
                    uint16_t  call_info;    /* call info for EX(This) */
                    uint16_t  extra;        /* not further specified */
                } u)
        } v;
        uint32_t type_info;
    } u1;
    union {
        uint32_t     next;                 /* hash collision chain */
        uint32_t     cache_slot;           /* cache slot (for RECV_INIT) */
        uint32_t     opline_num;           /* opline number (for FAST_CALL) */
        uint32_t     lineno;               /* line number (for ast nodes) */
        uint32_t     num_args;             /* arguments number for EX(This) */
        uint32_t     fe_pos;               /* foreach position */
        uint32_t     fe_iter_idx;          /* foreach iterator index */
        uint32_t     access_flags;         /* class constant access flags */
        uint32_t     property_guard;       /* single property guard */
        uint32_t     constant_flags;       /* constant flags */
        uint32_t     extra;                /* not further specified */
    } u2;
};
(gdb) p $2.value
$3 = {lval = 140737247576960, dval = 6.9533439118030153e-310, 
  counted = 0x7ffff1a60380, str = 0x7ffff1a60380, arr = 0x7ffff1a60380, 
  obj = 0x7ffff1a60380, res = 0x7ffff1a60380, ref = 0x7ffff1a60380, 
  ast = 0x7ffff1a60380, zv = 0x7ffff1a60380, ptr = 0x7ffff1a60380, 
  ce = 0x7ffff1a60380, func = 0x7ffff1a60380, ww = {w1 = 4054188928, 
    w2 = 32767}}
typedef union _zend_value {
    zend_long         lval;                /* long value */
    double            dval;                /* double value */
    zend_refcounted  *counted;
    zend_string      *str;
    zend_array       *arr;
    zend_object      *obj;
    zend_resource    *res;
    zend_reference   *ref;
    zend_ast_ref     *ast;
    zval             *zv;
    void             *ptr;
    zend_class_entry *ce;
    zend_function    *func;
    struct {
        uint32_t w1;
        uint32_t w2;
    } ww;
} zend_value;
(gdb) p *$3.arr
$4 = {gc = {refcount = 2, u = {type_info = 23}}, u = {v = {flags = 28 '\034', 
      _unused = 0 '\000', nIteratorsCount = 0 '\000', _unused2 = 0 '\000'}, 
    flags = 28}, nTableMask = 4294967294, arData = 0x7ffff1a67648, 
  nNumUsed = 3, nNumOfElements = 3, nTableSize = 8, nInternalPointer = 0, 
  nNextFreeElement = 3, pDestructor = 0x555555b6e200 <zval_ptr_dtor>}
struct _zend_array {
    zend_refcounted_h gc;
    union {
        struct {
            ZEND_ENDIAN_LOHI_4(
                zend_uchar    flags,
                zend_uchar    _unused,
                zend_uchar    nIteratorsCount,
                zend_uchar    _unused2)
        } v;
        uint32_t flags;
    } u;
    uint32_t          nTableMask;
    Bucket           *arData;
    uint32_t          nNumUsed;
    uint32_t          nNumOfElements;
    uint32_t          nTableSize;
    uint32_t          nInternalPointer;
    zend_long         nNextFreeElement;
    dtor_func_t       pDestructor;
};
(gdb) p *$4.arData
$5 = {val = {value = {lval = 2019, dval = 9.9751853895347677e-321, 
      counted = 0x7e3, str = 0x7e3, arr = 0x7e3, obj = 0x7e3, res = 0x7e3, 
      ref = 0x7e3, ast = 0x7e3, zv = 0x7e3, ptr = 0x7e3, ce = 0x7e3, 
      func = 0x7e3, ww = {w1 = 2019, w2 = 0}}, u1 = {v = {type = 4 '\004', 
        type_flags = 0 '\000', u = {call_info = 0, extra = 0}}, type_info = 4}, 
    u2 = {next = 0, cache_slot = 0, opline_num = 0, lineno = 0, num_args = 0, 
      fe_pos = 0, fe_iter_idx = 0, access_flags = 0, property_guard = 0, 
      constant_flags = 0, extra = 0}}, h = 0, key = 0x0}
$res = implode('-', [
    2019, '01', '01', [1,2]
]);
var_dump($res);
PHP Notice:  Array to string conversion in /path/to/t2.php on line 3
PHP Notice:  Array to string conversion in /path/to/t2.php on line 3
string(16) "2019-01-01-Array"
PHPAPI void php_implode(const zend_string *glue, zval *pieces, zval *return_value)
{
    zval         *tmp;
    int           numelems;
    zend_string  *str;
    char         *cptr;
    size_t        len = 0;
    struct {
        zend_string *str;
        zend_long    lval;
    } *strings, *ptr;
    ALLOCA_FLAG(use_heap)

    numelems = zend_hash_num_elements(Z_ARRVAL_P(pieces));

    if (numelems == 0) {
        RETURN_EMPTY_STRING();
    } else if (numelems == 1) {
        /* loop to search the first not undefined element... */
        ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
            RETURN_STR(zval_get_string(tmp));
        } ZEND_HASH_FOREACH_END();
    }

    ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap);

    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
        if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
            ptr->str = Z_STR_P(tmp);
            len += ZSTR_LEN(ptr->str);
            ptr->lval = 0;
            ptr++;
        } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
            zend_long val = Z_LVAL_P(tmp);

            ptr->str = NULL;
            ptr->lval = val;
            ptr++;
            if (val <= 0) {
                len++;
            }
            while (val) {
                val /= 10;
                len++;
            }
        } else {
            ptr->str = zval_get_string_func(tmp);
            len += ZSTR_LEN(ptr->str);
            ptr->lval = 1;
            ptr++;
        }
    } ZEND_HASH_FOREACH_END();

    /* numelems can not be 0, we checked above */
    str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0);
    cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
    *cptr = 0;

    while (1) {
        ptr--;
        if (EXPECTED(ptr->str)) {
            cptr -= ZSTR_LEN(ptr->str);
            memcpy(cptr, ZSTR_VAL(ptr->str), ZSTR_LEN(ptr->str));
            if (ptr->lval) {
                zend_string_release_ex(ptr->str, 0);
            }
        } else {
            char *oldPtr = cptr;
            char oldVal = *cptr;
            cptr = zend_print_long_to_buf(cptr, ptr->lval);
            *oldPtr = oldVal;
        }

        if (ptr == strings) {
            break;
        }

        cptr -= ZSTR_LEN(glue);
        memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue));
    }

    free_alloca(strings, use_heap);
    RETURN_NEW_STR(str);
}
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
        if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
            // ...
        } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
            // ...
        } else {
            // ...
        }
    } ZEND_HASH_FOREACH_END();
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
    if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
        // ...
    } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
        // ...
    } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_ARRAY)) {
        // 如果值是数组,则调用 php_implode,将其使用 glue 连接成字符串
        cptr = ZSTR_VAL(ptr->str);
        zend_string* str2 = origin_php_implode(glue, tmp, tmp_val);
        ptr->str = str2;
        // 此时,要拿到拼接后的字符串长度
        len += ZSTR_LEN(str2);
        ptr++;
    } else {
        // ...
    }
} ZEND_HASH_FOREACH_END();
static zend_string* origin_php_implode(const zend_string *glue, zval *pieces, zval *return_value)
{
    zval         *tmp;
    int           numelems;
    zend_string  *str;
    char         *cptr;
    size_t        len = 0;
    struct {
        zend_string *str;
        zend_long    lval;
    } *strings, *ptr;
    ALLOCA_FLAG(use_heap)

    numelems = zend_hash_num_elements(Z_ARRVAL_P(pieces));

    if (numelems == 0) {
        RETURN_EMPTY_STRING();
    } else if (numelems == 1) {
        /* loop to search the first not undefined element... */
        ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
            RETURN_STR(zval_get_string(tmp));
        } ZEND_HASH_FOREACH_END();
    }

    ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap);

    ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pieces), tmp) {
        if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
            ptr->str = Z_STR_P(tmp);
            len += ZSTR_LEN(ptr->str);
            ptr->lval = 0;
            ptr++;
        } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
            zend_long val = Z_LVAL_P(tmp);

            ptr->str = NULL;
            ptr->lval = val;
            ptr++;
            if (val <= 0) {
                len++;
            }
            while (val) {
                val /= 10;
                len++;
            }
        } else {
            ptr->str = zval_get_string_func(tmp);
            len += ZSTR_LEN(ptr->str);
            ptr->lval = 1;
            ptr++;
        }
    } ZEND_HASH_FOREACH_END();

    /* numelems can not be 0, we checked above */
    str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0);
    cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
    *cptr = 0;

    while (1) {
        ptr--;
        if (EXPECTED(ptr->str)) {
            cptr -= ZSTR_LEN(ptr->str);
            memcpy(cptr, ZSTR_VAL(ptr->str), ZSTR_LEN(ptr->str));
            if (ptr->lval) {
                zend_string_release_ex(ptr->str, 0);
            }
        } else {
            char *oldPtr = cptr;
            char oldVal = *cptr;
            cptr = zend_print_long_to_buf(cptr, ptr->lval);
            *oldPtr = oldVal;
        }

        if (ptr == strings) {
            break;
        }

        cptr -= ZSTR_LEN(glue);
        memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue));
    }

    free_alloca(strings, use_heap);
    // RETURN_NEW_STR(str);
    return str;
}
./configure
sudo make
sudo make install
$res = su_test('-', [
    2019, '01', '01', ['1', '2',],
]);
var_dump($res);
string(14) "2019-01-01-1-2"

关于PHP源码之implode函数源码怎么用就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. ThinkPHP源码学习 cookie函数 设置 取值 删除
  2. ThinkPHP源码学习 redirect函数 URL重定向

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php源码 implode函数

上一篇:mysql57的打开方法

下一篇:如何解决php响应Json字符串头部出现非法字符“\ufeff”的问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》