每天一个 PHP 语法六数组函数 array_keys、reset 的使用及实现

说明

这里基于php7.2.5进行测试,php7之后内部结构变化应该不是太大,但与php5.X有差别。

今天来学习下数组内置函数,这里用两个函数来作为例子进行。先看语法

array_keys ( array $array [, mixed $search_value = null [, bool $strict = false ]] ) : array
array_keys() 返回 input 数组中的数字或者字符串的键名。如果指定了可选参数 search_value,则只返回该值的键名。
否则 input 数组中的所有键名都会被返回。$strict是否严格模式

reset ( array &$array ) : mixed
reset()array 的内部指针倒回到第一个单元并返回第一个数组单元的值。
$params = [
    'name' => '愤怒的鸟',
    'total_mount' => 100,
    'remain_amount' => 8
];
print_r(array_keys($params));
print_r(array_keys($params, 100));
print_r(reset($params));

/*
Array
(
    [0] => name
    [1] => total_mount
    [2] => remain_amount
)
Array
(
    [0] => total_mount
)
愤怒的鸟
*/

我们之前说过函数分为用户自定义函数与内置函数以及数组的结构,忘了的看这里

来看array_keys的实现

PHP_FUNCTION(array_keys)
{
  // 第一个参数数组变量
    zval *input,                /* Input array */
    // 第二个可选参数值
         *search_value = NULL,    /* Value to search for */
         *entry,                /* An entry in the input array */
           new_val;                /* New value */
    zend_bool strict = 0;        /* do strict comparison */
    zend_ulong num_idx;
    zend_string *str_idx;
    zend_array *arrval;
    zend_ulong elem_count;

    ZEND_PARSE_PARAMETERS_START(1, 3)
        Z_PARAM_ARRAY(input)
        Z_PARAM_OPTIONAL
        Z_PARAM_ZVAL(search_value)
        Z_PARAM_BOOL(strict)
    ZEND_PARSE_PARAMETERS_END();
  // arrval返回hashTable Z_ARRVAL_P返回input指向的zend_value.arr
    arrval = Z_ARRVAL_P(input);
  // elem_count是数组元素个数  下面有解释
    elem_count = zend_hash_num_elements(arrval);

    /* Base case: empty input */
  // 元素个数为0 直接返回空数组
    if (!elem_count) {
        RETURN_ZVAL(input, 1, 0)
    }

    /* Initialize return array */
  // 如果没有第二个可选参数
    if (search_value != NULL) {
        array_init(return_value);

    // 是否是严格模式
        if (strict) {
            ZEND_HASH_FOREACH_KEY_VAL_IND(arrval, num_idx, str_idx, entry) {
                ZVAL_DEREF(entry);
                if (fast_is_identical_function(search_value, entry)) {
                    if (str_idx) {
                        ZVAL_STR_COPY(&new_val, str_idx);
                    } else {
                        ZVAL_LONG(&new_val, num_idx);
                    }
                    zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
                }
            } ZEND_HASH_FOREACH_END();
        } else {
            ZEND_HASH_FOREACH_KEY_VAL_IND(arrval, num_idx, str_idx, entry) {
                if (fast_equal_check_function(search_value, entry)) {
                    if (str_idx) {
                        ZVAL_STR_COPY(&new_val, str_idx);
                    } else {
                        ZVAL_LONG(&new_val, num_idx);
                    }
                    zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
                }
            } ZEND_HASH_FOREACH_END();
        }
    } else {
    // 获取整个数组的key
    // 复制元素个数
        array_init_size(return_value, elem_count);
        zend_hash_real_init(Z_ARRVAL_P(return_value), 1);
        ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
            if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
                /* Optimistic case: range(0..n-1) for vector-like packed array */
                ZVAL_LONG(&new_val, 0);
                for (; Z_LVAL(new_val) < elem_count; ++Z_LVAL(new_val)) {
                    ZEND_HASH_FILL_ADD(&new_val);
                }
            } else {
                /* Go through input array and add keys to the return array */
                ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
                    if (str_idx) {
                        ZVAL_STR_COPY(&new_val, str_idx);
                    } else {
                        ZVAL_LONG(&new_val, num_idx);
                    }
                    ZEND_HASH_FILL_ADD(&new_val);
                } ZEND_HASH_FOREACH_END();
            }
        } ZEND_HASH_FILL_END();
    }
}

#define Z_ARR(zval)                    (zval).value.arr
#define Z_ARR_P(zval_p)                Z_ARR(*(zval_p))

#define Z_ARRVAL(zval)                Z_ARR(zval)
#define Z_ARRVAL_P(zval_p)            Z_ARRVAL(*(zval_p))

// 返回数组元素个数
#define zend_hash_num_elements(ht)
    (ht)->nNumOfElements

小结:array_keys获取到数组的key,原理都是进行循环获取数组元素的索引值。

来看reset的实现

PHP_FUNCTION(reset)
{
    HashTable *array;
    zval *entry;

    ZEND_PARSE_PARAMETERS_START(1, 1)
        Z_PARAM_ARRAY_OR_OBJECT_HT_EX(array, 0, 1)
    ZEND_PARSE_PARAMETERS_END();

  // 操作在这里
    zend_hash_internal_pointer_reset(array);

    if (USED_RET()) {
        if ((entry = zend_hash_get_current_data(array)) == NULL) {
            RETURN_FALSE;
        }

        if (Z_TYPE_P(entry) == IS_INDIRECT) {
            entry = Z_INDIRECT_P(entry);
        }

        ZVAL_DEREF(entry);
        ZVAL_COPY(return_value, entry);
    }
}

ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos)
{
    uint32_t idx;

    IS_CONSISTENT(ht);
    HT_ASSERT(ht, &ht->nInternalPointer != pos || GC_REFCOUNT(ht) == 1);

  // 循环这个数组,直到第一个有效的元素,返回这个元素
    for (idx = 0; idx < ht->nNumUsed; idx++) {
        if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) {
            *pos = idx;
            return;
        }
    }
    *pos = HT_INVALID_IDX;
}

小结:reset会循环元素直到返回有效的元素值停止。

参考资料:《PHP7内核剖析》

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!