3 回答
TA貢獻1811條經驗 獲得超6個贊
1. at the beginning of foreach: ZEND_FE_RESET which increase the refoucnt of $a
2. then FE_FETCH, reset internal pointer of $a
3. then current, current declared to accept a reference, but $a is not a ref and refcount > 1 , then -> separation
TA貢獻1868條經驗 獲得超4個贊
foreach() 操作原始數組的一個拷貝,如果需要移動指針,使用 while 結構加上 each() 來實現。
$arr = array ('a', 'b', 'c', 'd', 'e');reset($arr);while (list($k, $v) = each($arr)) { # 當前指針已經被指向了下一位
$curr = current($arr);
echo "{$k} => {$v} -- {$curr}\n";
}TA貢獻1784條經驗 獲得超7個贊
php的所有變量實際上是用一個struct zval來表示的。
/* Zend/zend.h */typedef struct _zval_struct zval;typedef union _zvalue_value { long lval; /* long value */
double dval; /* double value */
struct { char *val; int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;struct _zval_struct { /* Variable information */
zvalue_value value; /* value */
zend_uint refcount;
zend_uchar type; /* active type */
zend_uchar is_ref;
};而數組就是其中的"HashTable *ht",實際上就是一個哈希表(Hash Table),表中的所有元素同時又組成一個雙向鏈表,它的定義為:
/* Zend/zend_hash.h */typedef struct _hashtable { uint nTableSize; uint nTableMask; uint nNumOfElements; ulong nNextFreeElement;
Bucket *pInternalPointer; /* Used for element traversal */
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;#if ZEND_DEBUG
int inconsistent;#endif} HashTable;這里有一個 Bucket *pInternalPointer ,就是被reset/current/next等函數用來遍歷數組保存位置狀態的。Bucket的實現如下,可以看到這就是個赤裸裸的鏈表節點。
typedef struct bucket { ulong h; /* Used for numeric indexing */
uint nKeyLength; void *pData; void *pDataPtr; struct bucket *pListNext; struct bucket *pListLast; struct bucket *pNext; struct bucket *pLast; char arKey[1]; /* Must be last element */} Bucket;而foreach的實現,則位于 ./Zend/zend_compile.h ,在解釋期被flex翻譯成由 zend_do_foreach_begin zend_do_foreach_cont zend_do_foreach_end 這三個函數(以及相關代碼)組合起來。
- 3 回答
- 0 關注
- 167 瀏覽
添加回答
舉報
