php如何移動數組內部指標

來源:互聯網
上載者:User
php的數組都有一個內部指標,指向數組的元素,初始化的時候是第一個,我要便利數組,讓內部指標逐個移動

$arr = array ('a', 'b', 'c', 'd', 'e');foreach ($arr as $k => $v) {    $curr = current($arr);    echo "{$k} => {$v} -- {$curr}\n";}

得到結果是

0 => a -- b1 => b -- b2 => c -- b3 => d -- b4 => e -- b

內部指標向後移動了一位就再也沒動過了。。。
foreach對這個數組做了什麼呢?為什麼呢?
我要讓指標遍曆數組,得到如下結果改怎麼做呢?

0 => a -- a1 => b -- b2 => c -- c3 => d -- d4 => e -- e

回複內容:

php的數組都有一個內部指標,指向數組的元素,初始化的時候是第一個,我要便利數組,讓內部指標逐個移動

$arr = array ('a', 'b', 'c', 'd', 'e');foreach ($arr as $k => $v) {    $curr = current($arr);    echo "{$k} => {$v} -- {$curr}\n";}

得到結果是

0 => a -- b1 => b -- b2 => c -- b3 => d -- b4 => e -- b

內部指標向後移動了一位就再也沒動過了。。。
foreach對這個數組做了什麼呢?為什麼呢?
我要讓指標遍曆數組,得到如下結果改怎麼做呢?

0 => a -- a1 => b -- b2 => c -- c3 => d -- d4 => e -- e

這個問題我在bugs.php.net上回答過: https://bugs.php.net/bug.php?id=63752

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

PHP 的數組指標操作函數:

  1. pos() http://cn2.php.net/manual/en/function...
  2. end() http://cn2.php.net/manual/en/function...
  3. prev() http://cn2.php.net/manual/en/function...
  4. next() http://cn2.php.net/manual/en/function...
  5. each() http://cn2.php.net/manual/en/function...
  6. reset() http://cn2.php.net/manual/en/function...
  7. current() http://cn2.php.net/manual/en/function...
"Also note that foreach operates on a copy of the specified array, not the array itself, therefore the array pointer is not modified as with the each() construct and changes to the array element returned are not reflected in the original array."
http://cn2.php.net/manual/en/control-...

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";}

參見 http://cn2.php.net/manual/en/function... 的 example #2。

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 這三個函數(以及相關代碼)組合起來。由於看起來比較晦澀,我就不貼出來了(實際上我也沒看太懂),詳情可以參考雪候鳥的這篇:深入理解PHP原理之foreach

最後附一段php代碼的opcode


number of ops:  12compiled vars:  !0 = $arr, !1 = $xline  # *  op                   return  operands-----------------------------------------------------2     0  >   INIT_ARRAY           ~0      1         用1初始化數組      1      ADD_ARRAY_ELEMENT    ~0      2         添加個2      2      ADD_ARRAY_ELEMENT    ~0      3         添加個3      3      ASSIGN                       !0, ~0    存入$arr3     4    > FE_RESET             $2      !0, ->10  $2 = FE_RESET($arr), 失敗則跳到#10      5  > > FE_FETCH             $3      $2, ->10  $3 = FE_FETCH($2), 失敗則跳到#10      6  >   ZEND_OP_DATA                                 7      ASSIGN                       !1, $3    $x = $34     8      ECHO                         !1        echo $x      9    > JMP                          ->5       跳到#5     10  >   SWITCH_FREE                  $2        釋放$25    11    > RETURN                       1         返回
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.