您的位置 首页 php

每天一个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 {
    // 获取整个数组的keys
    // 复制元素个数
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内核剖析》

文章来源:智云一二三科技

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

文章地址:https://www.zhihuclub.com/78026.shtml

关于作者: 智云科技

热门文章

网站地图