说明
这里基于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内核剖析》
海报
0 条评论
155
相关文章
本站已关闭游客评论,请登录或者注册后再评论吧~