先看如下**
<?php
$arr = [1, 2, 3];
foreach ($arr as &$item)
echo "\n\n";
foreach ($arr as $item)
預期結果應該是
int(1)
int(2)
int(3)
int(1)
int(2)
int(3)
[finished in 0.1s]
執行結果卻是
int(1)
int(2)
int(3)
int(1)
int(2)
int(2)
[finished in 0.1s]
**改為
<?php
$arr = [1, 2, 3];
foreach ($arr as &$item)
unset($item);
echo "\n\n";
foreach ($arr as $item)
結果就正常了
說原因之前,先了解下zval的大致結構:
「zval結構體中有四個字段,其含義分別為:
屬性名 含義 預設值
refcount__gc 表示引用計數 1
is_ref__gc 表示是否為引用 0
value 儲存變數的值
type 變數具體的型別」
摘錄來自: reeze xia. 「tipi: 深入理解php核心」。
利用xdebug擴充套件,可以看到refcount和is_ref的情況:
<?php
$a = "hello world";
xdebug_debug_zval('a');
然後在php7下執行:
a: (refcount=2, is_ref=0)='hello world'
在php5.5下執行:(我沒試過,因為環境都是php7)
a: (refcount=1, is_ref=0)='hello world'
為什麼7的refcount 為2呢?這裡是php7的字面量也計算了一次次數
<?php
$a = "hello world";
$b = $a . $a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
結果為:
a: (refcount=2, is_ref=0)='hello world'
b: (refcount=1, is_ref=0)='hello worldhello world'
加上引用符號的時候:
<?php
$a = "hello world";
$b = &$a;
xdebug_debug_zval('a');
xdebug_debug_zval('b');
結果為:
a: (refcount=2, is_ref=1)='hello world'
b: (refcount=2, is_ref=1)='hello world'
foreach 內部的實現類似於:
foreach具體實現
foreach ($arr as $k => $item)
$item = $arr[$k];
foreach ($arr as $k => &$item)
$item = &$arr[$k];
第一次foreach結束的時候, item並沒有釋放掉,item為arr[k]的引用
所以在第二次foreach的時候,item始終為陣列最後乙個元素的引用,迴圈的每次,都給陣列最後一項進行了賦值操作
所以在倒數第二次的迴圈的時候,給最後一項賦值了倒數第二項的值。進行最後一次迴圈的時候,值為倒數第二項的值,最後一項的值已經丟掉了
在第二次進行迴圈的時候,給item進行一次unset操作,因為item是對arr[k]的引用,檢視zval如下
item:(refcount=2, is_ref=1)int 1
item:(refcount=2, is_ref=1)int 2
item:(refcount=2, is_ref=1)int 3
進行unset操作只是對應的變數的refcount減1,並不會刪除變數內容
所以第二次的結果就正常了
php的引用計數是對於記憶體進行的優化,給變數賦值操作的話,不進行拼接等操作,只是引用計數增加,並不會增加記憶體空間的占用
對於只是記憶體操作的話,比如拼裝where條件等(php7.1之後,支援型別限制)
function test_mem(array $arr) : array
return $arr;
}
如果有io操作,比如資料庫操作,http呼叫操作(進一步可以使用try catch)
函式的返回值標識執行結果的成功與失敗,函式的返回引數通過傳進去乙個空的變數,通過這個變數拿出來
function test_io(array &$resp, array $params) : bool
return true;
}
php原生函式,ksort函式的引數就是引用傳值
<?php
function test_go(array $params) : array
$ret['data'] = $params;
$ret['msg'] = 'success';
$ret['status'] = true;
return $ret;
}$data = ;
$msg = '';
$status = false;
$params = [1,2,3,4,5,6];
[$data, $msg, $status] = test_go($params);
深入理解php7核心之zval
比如這種
struct _zval_struct str;
hashtable *ht;
zend_object_value obj;
zend_ast *ast;
} value;
zend_uint refcount__gc;
zend_uchar type;
zend_uchar is_ref__gc;
};
簡單介紹下for each迴圈的使用
通常我們使用的迴圈語句有3,分別是 1.for int i 0 i 2.while 3.do while 常用一般是for迴圈。但是,在工作中,大量複寫for既繁瑣,又容易導致出錯 博主經常分不清哪個 是哪個的 所以經過老師的講解,學習了for each的使用。列子1 如果申明乙個陣列字串,如何使用...
涉及 C 的 foreach問題
當時是用foreach實現遍歷,但是函式傳入引數是object型別的,由於objectl型別沒有實現相關介面,所以foreach並不能執行。那麼下面我們來看看,想要使用foreach需要具備什麼條件。需要實現ienumerable介面或宣告getenumerator方法的型別。下面我們來看看fore...
foreach中引用 的問題
在工作中遇到 關於 php foreach 引用的乙個問題 簡單來說,如下 arr array a b c d foreach arr as k v foreach arr as k v print r arr 結果是 ab cc參考了 這篇文章,以及 這篇文章 在第一次foreach 遍歷結束後,...