PHP中引用傳遞+unset+global理解,但願大神指正

關鍵是對global的誤解,以前覺得在函數中global變量,就是把函數外部的變量拿進函數內部使用,但彷佛我錯了
引用傳遞+unset+global理解php

php的引用(就是在變量、函數、對象等前面加上&符號)
在PHP中引用的意思是:不一樣的名字訪問同一個內存地址數組

一、變量的引用:PHP的引用容許你用兩個變量來指向同一個內存空間
代碼:框架

clipboard.png

結果:函數

clipboard.png

二、函數的傳址調用性能

clipboard.png

這裏$num傳遞給函數的實際上是$num所處的內存地址,經過在函數裏改變$a的值,就能夠改變$num的值了優化

三、函數的引用返回 —— 沒太明白何時用
和參數傳遞不一樣,函數的引用返回必須在兩個地方都用 & 符號(函數聲明時、函數調用時) —— 指出返回的是一個引用,而不是一般的一個拷貝this

clipboard.png

結果:spa

clipboard.png

clipboard.png

結果:指針

clipboard.png

clipboard.png

結果:對象

clipboard.png

clipboard.png

結果:

clipboard.png

下面解釋下:
儘管函數聲明方式是 function &test() 這樣,但經過$a = test() 這種方式的函數調用獲得的其實不是函數的引用返回,這跟普通的函數調用沒有區別
PHP規定經過 $a = &test() 而且在聲明函數時也使用了&,獲得的纔是函數的引用返回
用上面的例子來解釋就是,$a = test() 這種方式調用函數,只是將函數的返回值賦給 $a 而已,而$a作任何改變都不會影響到函數中的$b

而經過 $a = &test() 方式調用函數呢(前提是聲明函數時也用了&),它的做用是將 return $b 中的 $b 變量的內存地址與 $a 變量的內存地址指向了同一個地方。即產生了至關於這樣的效果 ($a=&$b), 因此改變 $a 的值也同時改變了 $b 的值。因此在執行了
$a = &test();
$a = 5;
之後,$b的值也變爲了5

再來個例子加深理解:
PHP裏的函數的引用在定義及調用都要在函數名前加上 &

clipboard.png

結果:

clipboard.png

這裏是爲了讓你們理解函數的引用返回才使用靜態變量的,其實函數的引用返回多用在對象中
不少時候咱們會看到這樣的代碼(出自 CI 框架源碼):
$class =& load_class('a','b');

手冊裏是這麼寫的:引用返回用在當想用函數找到引用應該被綁定在哪個變量上面時。不要用返回引用來增長性能,引擎足夠聰明來本身進行優化。僅在有合理的技術緣由時才返回引用!要返回引用,使用此語法:

clipboard.png

和參數傳遞不一樣,這裏必須在兩個地方都用 & 符號——指出返回的是一個引用,而不是一般的一個拷貝,一樣也指出 $myValue 是做爲引用的綁定,而不是一般的賦值
若是試圖這樣從函數返回引用:return ($this->value);,這將不會起做用,由於在試圖返回一個表達式的結果而不是一個引用的變量。只能從函數返回引用變量——沒別的方法。若是代碼試圖返回一個動態表達式或 new 運算符的結果,自 PHP 4.4.0 和 PHP 5.1.0 起會發出一條 E_NOTICE 錯誤
似懂非懂?那麼咱們來改寫一下程序吧,讓它變成一個常規的函數:

clipboard.png

結果:

clipboard.png

如今能理解「引用返回用在當想用函數找到引用應該被綁定在哪個變量上面時」這句話了吧,函數 &getValue() 把引用綁定在成員變量 $value 上了。正常來講,$obj = new foo; 產生的 $obj 是一個copy,它的成員變量 $value 與函數 getValue() 不存在「別名」(引用)關係(額,不太懂)

四、對象的引用

clipboard.png

結果:

clipboard.png

以上代碼是在PHP5中的運行效果,在PHP5中對象的複製是經過引用來實現的。上列中$b=new a; $c=$b; 其實等效於$b=new a; $c=&$b; PHP5中默認就是經過引用來調用對象, 但有時你可能想創建一個對象的副本,並但願原來的對象的改變不影響到副本,爲了這樣的目的,PHP定義了一個特殊的方法,稱爲__clone
php5中對於大數組的傳遞,建議用 "&" 方式,畢竟節省內存空間使用

五、取消引用
重要的是刪除引用的變量,當你 unset 一個引用,只是斷開了變量名和內存地址之間的綁定。只是unset的變量訪問不了,這並不意味着內存地址被銷燬了

clipboard.png

不會 unset $b,只是 $a

clipboard.png

地址(引用)傳遞,只是多個變量指向了同一地址(內存空間)
unset一個,並不能unset掉地址空間

根據這個原理,咱們來屢屢$a和$GLOBALS['a']之間的關係
代碼1:

clipboard.png

代碼2:

clipboard.png

結果:

clipboard.png

代碼3:

clipboard.png

結果:

clipboard.png

根據這三段代碼的結果,$a和$GLOBALS['a']在內存中的關係確定不是這樣的

clipboard.png

若是是這樣的話,unset掉一個,另外一個應該仍是存在的
因此我的猜想關係應該是這樣的:

clipboard.png

其中一個是另外一個的別名
關於這個問題,也問了一些人,各有個的說法,何況都牽扯到了PHP底層機制,暫且放一放,按照上面說的來理解吧

六、global

clipboard.png

這裏的$num =& $GLOBALS['num']; $num是函數裏的$num,函數裏的$num指向了$GLOBALS['num']的內存地址

clipboard.png

global 引用
當在函數中用 global $var 聲明一個變量時實際上創建了一個到全局變量的引用。也就是說和這樣作是相同的:
$var =& $GLOBALS["var"];
這意味着,unset $var 不會 unset 全局變量

$this 在一個對象的方法中,永遠是調用它的對象的引用

再來一個例子:

clipboard.png

結果:

clipboard.png

爲何會是0 5呢?
global在函數中產生一個指向函數外部變量的別名變量,而不是真的把函數外的變量拿到函數中使用
一旦改變了別名變量(函數內部的變量)的指向地址
$var2 =& $var1;
其實就是函數中$var2的引用指向了$var1的內存地址
只是函數中$var2的指向發生了變化,函數內部變量的變化只在函數的局部產生效應,在函數外部$var2的指向物理內存地址並無變化,仍是它本身,因此根本就沒有改變函數外$var2的值
$GLOBALS[]確確實實調用的是函數外部的變量,函數內外始終保持一致!

clipboard.png

結果:

clipboard.png

七、寫時拷貝
php中對於地址的指向(相似指針)功能不是由用戶本身來實現的,是由Zend核心實現的,php中引用採用的是寫時拷貝的原理,就是除非發生寫操做,指向同一個地址的變量或者對象是不會被拷貝的
通俗的講:
① 若是有下面的代碼
$a="ABC"; $b=$a;
其實此時,$a與$b都是指向同一內存地址,而並非$a與$b佔用不一樣的內存
② 若是在上面的代碼基礎上再加上以下代碼
$a="EFG";
因爲$a與$b所指向的內存的數據要從新寫一次了,此時Zend核心會自動判斷,自動爲$b產生一個$a的數據拷貝,從新申請一塊內存進行存儲

clipboard.png

相關文章
相關標籤/搜索