最近研讀PHP變量構(gòu)造的資料時(shí)辉饱,發(fā)現(xiàn)了自己一直以來對傳值和傳址賦值理解存在很大的誤區(qū)额获。
之前的理解是這樣子的:
1.傳值是將值復(fù)制一份傳遞給新變量,二者的數(shù)據(jù)不在同一個(gè)地址空間中获雕。
2.傳址是新變量指向了傳址變量的地址牺弄,二者數(shù)據(jù)在同一個(gè)地址空間中焕襟。
不知道大家理解的是不是和我一樣。但是1中的理解是存在問題的肛搬。?傳值賦值變量也指向同一個(gè)地址没佑,直到最后某個(gè)變量的值發(fā)生變化,指向的數(shù)據(jù)地址空間才會分離?滚婉。
接下來是對這個(gè)觀點(diǎn)的驗(yàn)證图筹,驗(yàn)證之前了解一下知識:
要理解這個(gè)先要引入關(guān)鍵詞“zval”。zval結(jié)構(gòu)體是PHP變量在內(nèi)核中的表單方式让腹。在這個(gè)結(jié)構(gòu)體重有4個(gè)成員變量需要知道:
1.refcount:變量引用計(jì)數(shù)器远剩,指這個(gè)變量被多少個(gè)變量引用。
2.type:變量類型骇窍,存儲的數(shù)據(jù)類型“IS_LONG","IS_STRING”等值瓜晤。
3.is_ref:變量是否被引用。
先驗(yàn)證傳值腹纳,代碼如下:
$c=1;xdebug_debug_zval('c');$d=$c;$e=$c;xdebug_debug_zval('c');$c+=1;xdebug_debug_zval('c');xdebug_debug_val('d');
結(jié)果如下:
發(fā)現(xiàn)了沒有當(dāng)$d = $c;的時(shí)候痢掠,refcount = 3說明數(shù)據(jù)內(nèi)存地址被引用了兩次;當(dāng)$c值發(fā)送改變的時(shí)候$c的zval中的refcount = 1嘲恍;$d的zval的refcount此時(shí)也減少1足画,因?yàn)橹蛋l(fā)生了變化$c引用了另一個(gè)數(shù)據(jù)地址空間。
我們稍微改一下代碼佃牛,驗(yàn)證一下傳址淹辞,代碼如下:
$c=1;xdebug_debug_zval('c');$d=&$c;$e=&$c;xdebug_debug_zval('c');$c+=1;xdebug_debug_zval('c');xdebug_debug_zval('d');
只是把傳值改成功了傳址,結(jié)果如下:
看前面兩個(gè)輸出值俘侠,和上面?zhèn)髦档慕Y(jié)果是不是一致呢象缀?完全一致!說明不管是傳值還是傳址賦值時(shí)都指向了同一個(gè)地址空間爷速。只是在數(shù)據(jù)變化的時(shí)候二者才會表現(xiàn)不一致央星。
其實(shí)從宏觀上看,這樣的設(shè)計(jì)是非常有好處的惫东。如果按照之前的理解是成立的話莉给,傳值賦值都會復(fù)制一份值的給另一個(gè)變量,那么$c是一個(gè)非常大的字符串的時(shí)候,復(fù)制一份就造成了內(nèi)存很多浪費(fèi)颓遏。而值一致都變量都指向同一個(gè)數(shù)據(jù)地址空間胁黑,這就能有效的減少內(nèi)存開銷了。