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 關注
- 153 瀏覽
添加回答
舉報