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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章