PHP源码分析array_splic()

2016/07/31

PHP源码分析 数组分割.

PHP_array_splic()

array array_splice ( array &$input , int $offset int $length = 0 bool $preserve_keys ] ) 有四个参数 第一个是输入数组,第二个是偏移量 ,第三个是截取长度默认是input的长度, 第四个是bool代表返回的数组是否保留之前的key

 PHP_FUNCTION(array_slice)
    {
    zval     *input,        /* 输入的数组 */
        **z_length = NULL, /* 数组长度 */ 
        **entry;        
    long     offset,        /* 起始偏移位置 */
    length = 0;    /* 返回数组长度 */
    zend_bool preserve_keys = 0; /* 是否重置索引 默认不重置 */
    int      num_in,        /* 输入数组的长度 */
             pos;           /* 当前的指针 */
    char *string_key;
    uint string_key_len;
    ulong num_key;
    HashPosition hpos;

    /* 判断参数个数和类型是否正确 */
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|Zb", &input, &offset, &z_length, &preserve_keys) == FAILURE) {
    return;
    }

    /*  输入的数组的元素个数 */
    num_in = zend_hash_num_elements(Z_ARRVAL_P(input));

    /* 如果没有传第三个参数 让length = num_in */
    if (ZEND_NUM_ARGS() < 3 || Z_TYPE_PP(z_length) == IS_NULL)     {
    length = num_in;
    } else {
    convert_to_long_ex(z_length); /* 强制转换z_length 为 long 类型 */
    length = Z_LVAL_PP(z_length); 
    }

    /* 如果偏移量大于输入数组的长度 返回null */
    if (offset > num_in) {
      array_init(return_value);
      return;
    } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
      offset = 0; /* offset 可以为负数 但是如果 offset 加上 输入数组的长度小于0 就让offset = 0  同时也让offset 为>=0*/
    }

    /* 计算length 的长度 */
    if (length < 0) {
      length = num_in - offset + length;
    } else if (((unsigned long) offset + (unsigned long) length) > (unsigned) num_in) {
      length = num_in - offset;
    }

    /* 初始化返回数组 */
    array_init_size(return_value, length > 0 ? length : 0);

    if (length <= 0) {
        return;
    }

    /* 把pos 指向 数组input中 offset处 */
    pos = 0;
    zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &hpos);
    while (pos < offset && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {
        pos++;
        zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
    }

    /* 把元素复制到return_value上 */
    while (pos < offset + length && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {

    zval_add_ref(entry);

    switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &hpos)) {
        case HASH_KEY_IS_STRING:
            zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL);
            break;

        case HASH_KEY_IS_LONG:
            if (preserve_keys) {
                zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL);
            } else {
                zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
            }
            break;
    }
    pos++;
    zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
    }
    }
下面是用PHP翻译过来的
function slice($input,$offset,$length,$preserve_keys)
{
$num_in = count($input);

if ($length === null) {
    $length = $num_in;
}

if ($offset < 0 && ($offset = ($num_in + $offset)) < 0) {
    $offset = 0;
} elseif ($offset > $num_in) {
    return;
}

if ($length > 0 && ($length + $offset) > $num_in) {
    $length = $num_in - $offset;
} elseif ($length < 0) {
    $length = $num_in - $offset + $length;
}

while ($offset--) {
    next($input);
}

$result_array = array();
while ($length--) {
    if ($preserve_keys) {
        $result_array[key($input)] = current($input);
    } else {
        $result_array[] = current($input);
    }
    next($input);
}

 return $result_array;
}

Post Directory