php获取数组第一个和最后一个元素的key

PHP 7.3.0之前的版本获取数组第一个和最后一个元素的key的几种方法。

$a = [
   'one' => 1,
    'two' => 2,
    'three' => 3
];

方法一

$first = reset($a);
$first_key = key($a);

$last = end($a);
$last_key = key($a);

方法二

$keys = array_keys($a);
$first = reset($keys);
$last = end($keys);

可以使用array_keys(),但是这样做的效率可能相当低。
也可以使用reset()和key(),但是这可能会改变内部数组指针。
PHP 7.3.0 加入两个函数解决这些问题了。
see https://www.php.net/manual/zh/function.array-key-last.php

  • array_key_first
  • array_key_last
    看看它们是如果实现的。源码加了一些中文注释方便理解。
    文件在 array.c : 3952
PHP_FUNCTION(array_key_first)
{
	zval *stack;    /* 传入数组 */

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ARRAY(stack) 
	ZEND_PARSE_PARAMETERS_END();

	HashTable *target_hash = Z_ARRVAL_P (stack);
	HashPosition pos = 0;   //位置0
	zend_hash_get_current_key_zval_ex(target_hash, return_value, &pos); // 根据位置取数组的key
}
ZEND_API void ZEND_FASTCALL zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos)
{
	uint32_t idx = *pos;
	Bucket *p;

	IS_CONSISTENT(ht);
	if (idx >= ht->nNumUsed) { //检查数组位置是否下超过数组实际使用最大元素的个数
		ZVAL_NULL(key);
	} else {
		if (idx == 0) {
			idx = _zend_hash_get_first_pos(ht); // 查找第个一有效元素的位置,因为位置0的元素可能被删除。
			if (idx >= ht->nNumUsed) {
				ZVAL_NULL(key);
				return;
			}
		}
		p = ht->arData + idx; // 根据位置找到第一个元素
		if (p->key) {    // 判断是关键数组,还是索引数组
			ZVAL_STR_COPY(key, p->key); //返回关键数组key
		} else {
			ZVAL_LONG(key, p->h);   //返回索引数组key
		}
	}
}

PHP_FUNCTION(array_key_last)
{
	zval *stack;    /* 传入数组 */
	HashPosition pos; // 最后一个有效元素的位置

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ARRAY(stack)
	ZEND_PARSE_PARAMETERS_END();

	HashTable *target_hash = Z_ARRVAL_P (stack);
	zend_hash_internal_pointer_end_ex(target_hash, &pos);   //获取最后一个有效元素的位置
	zend_hash_get_current_key_zval_ex(target_hash, return_value, &pos); //根据位置取数组的key
}
ZEND_API void ZEND_FASTCALL zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos)
{
	uint32_t idx;

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

	idx = ht->nNumUsed;  // 位置等于数组实际使用最大元素的个数
	while (idx > 0) {
		idx--;       // 从后住前递减
		if (Z_TYPE(ht->arData[idx].val) != IS_UNDEF) { // 查找元素是否有效
			*pos = idx;                               
			return;
		}
	}
	*pos = ht->nNumUsed;
}

你可能感兴趣的:(PHP)