php的引用(就是在變量或者函數、對象等前面加上&符號)
在PHP 中引用的意思是:不一樣的名字訪問同一個變量內容。
與C語言中的指針是有差異的.C語言中的指針裏面存儲的是變量的內容,在內存中存放的地址。
1.變量的引用
PHP 的引用容許你用兩個變量來指向同一個內容php
<?php $a="ABC"; $b =&$a; echo $a;//這裏輸出:ABC echo $b;//這裏輸出:ABC $b="EFG"; echo $a;//這裏$a的值變爲EFG 因此輸出EFG echo $b;//這裏輸出EFG ?>
2.函數的引用傳遞(傳址調用)數組
傳址調用我就很少說了 下面直接給出代碼ide
<?php function test(&$a){ $a=$a+100; } $b=1; echo $b;//輸出1 test($b); //這裏$b傳遞給函數的實際上是$b的變量內容所處的內存地址,經過在函數裏改變$a的值 就能夠改變$b的值了 echo "<br>"; echo $b;//輸出101 ?>
2.函數的引用傳遞(傳址調用)函數
傳址調用我就很少說了 下面直接給出代碼性能
<?php function test(&$a){ $a=$a+100; } $b=1; echo $b;//輸出1 test($b); //這裏$b傳遞給函數的實際上是$b的變量內容所處的內存地址,經過在函數裏改變$a的值 就能夠改變$b的值了 echo "<br>"; echo $b;//輸出101 ?>
要注意的是,在這裏test(1);的話就會出錯,緣由本身去想。測試
注意:this
上面的「 test($b); 」 中的$b前面不要加 & 符號,可是在函數「call_user_func_array」中,若要引用傳參,就得須要 & 符號,以下代碼所示:spa
<?php function a(&$b){ $b++; } $c=0; call_user_func_array('a',array(&$c)); echo $c; //輸出 1 ?>
3.函數的引用返回 .net
先看代碼指針
<?php function &test(){ static $b=0;//申明一個靜態變量 $b=$b+1; echo $b; return $b; } $a=test();//這條語句會輸出 $b的值 爲1 $a=5; $a=test();//這條語句會輸出 $b的值 爲2 $a=&test();//這條語句會輸出 $b的值 爲3 $a=5; $a=test();//這條語句會輸出 $b的值 爲6 ?>
下面解釋下:
經過這種方式$a=test();獲得的其實不是函數的引用返回,這跟普通的函數調用沒有區別 至於緣由: 這是PHP的規定
PHP規定經過$a=&test(); 方式獲得的纔是函數的引用返回
至於什麼是引用返回呢(PHP手冊上說:引用返回用在當想用函數找到引用應該被綁定在哪個變量上面時。) 這句狗屁話 害我半天沒看懂
用上面的例子來解釋就是
$a=test()方式調用函數,只是將函數的值賦給$a而已, 而$a作任何改變 都不會影響到函數中的$b
而經過$a=&test()方式調用函數呢, 他的做用是 將return $b中的 $b變量的內存地址與$a變量的內存地址 指向了同一個地方
即產生了至關於這樣的效果($a=&$b;) 因此改變$a的值 也同時改變了$b的值 因此在執行了
$a=&test();
$a=5;
之後,$b的值變爲了5
這裏是爲了讓你們理解函數的引用返回才使用靜態變量的,其實函數的引用返回多用在對象中
另附一個php官方例子:
This is the way how we use pointer to access variable inside the class. <?php class talker{ private $data = 'Hi'; public function & get(){ return $this->data; } public function out(){ echo $this->data; } } $aa = new talker(); $d = &$aa->get(); $aa->out(); $d = 'How'; $aa->out(); $d = 'Are'; $aa->out(); $d = 'You'; $aa->out(); ?> the output is "HiHowAreYou"
4.對象的引用
<?php class a{ var $abc="ABC"; } $b=new a; $c=$b; echo $b->abc;//這裏輸出ABC echo $c->abc;//這裏輸出ABC $b->abc="DEF"; echo $c->abc;//這裏輸出DEF ?>
以上代碼是在PHP5中的運行效果
在PHP5中 對象的賦值是個引用的過程。上列中$b=new a; $c=$b; 其實等效於$b=new a; $c=&$b;
PHP5中默認就是經過引用來調用對象, 但有時你可能想創建一個對象的副本,並但願原來的對象的改變不影響到副本 . 爲了這樣的目的,PHP5定義了一個特殊的方法,稱爲__clone。
在php4中,對象的賦值是個拷貝過程,
如:$b=new a,其中new a產生的是一個匿名的a對象實例,而此時的$b是對這個匿名對象的拷貝。同理$c=$b,也是對$b內容的一個拷貝。因此在php4中,爲了節省內存空間,$b=new a 通常會改爲引用的模式,即 $b=& new a。
下面再來個 官方 提供的例子:
在php5中,你不須要額外添加什麼東西就可到達「對象引用」的功能:
<?php class foo{ protected $name; function __construct($str){ $this->name = $str; } function __toString(){ return 'my name is "'. $this->name .'" and I live in "' . __CLASS__ . '".' . "\n"; } function setName($str){ $this->name = $str; } } class MasterOne{ protected $foo; function __construct($f){ $this->foo = $f; } function __toString(){ return 'Master: ' . __CLASS__ . ' | foo: ' . $this->foo . "\n"; } function setFooName($str){ $this->foo->setName( $str ); } } class MasterTwo{ protected $foo; function __construct($f){ $this->foo = $f; } function __toString(){ return 'Master: ' . __CLASS__ . ' | foo: ' . $this->foo . "\n"; } function setFooName($str){ $this->foo->setName( $str ); } } $bar = new foo('bar'); print("\n"); print("Only Created \$bar and printing \$bar\n"); print( $bar ); print("\n"); print("Now \$baz is referenced to \$bar and printing \$bar and \$baz\n"); $baz =& $bar; print( $bar ); print("\n"); print("Now Creating MasterOne and Two and passing \$bar to both constructors\n"); $m1 = new MasterOne( $bar ); $m2 = new MasterTwo( $bar ); print( $m1 ); print( $m2 ); print("\n"); print("Now changing value of \$bar and printing \$bar and \$baz\n"); $bar->setName('baz'); print( $bar ); print( $baz ); print("\n"); print("Now printing again MasterOne and Two\n"); print( $m1 ); print( $m2 ); print("\n"); print("Now changing MasterTwo's foo name and printing again MasterOne and Two\n"); $m2->setFooName( 'MasterTwo\'s Foo' ); print( $m1 ); print( $m2 ); print("Also printing \$bar and \$baz\n"); print( $bar ); print( $baz ); ?>
輸出:
Only Created $bar and printing $bar my name is "bar" and I live in "foo". Now $baz is referenced to $bar and printing $bar and $baz my name is "bar" and I live in "foo". Now Creating MasterOne and Two and passing $bar to both constructors Master: MasterOne | foo: my name is "bar" and I live in "foo". Master: MasterTwo | foo: my name is "bar" and I live in "foo". Now changing value of $bar and printing $bar and $baz my name is "baz" and I live in "foo". my name is "baz" and I live in "foo". Now printing again MasterOne and Two Master: MasterOne | foo: my name is "baz" and I live in "foo". Master: MasterTwo | foo: my name is "baz" and I live in "foo". Now changing MasterTwo's foo name and printing again MasterOne and Two Master: MasterOne | foo: my name is "MasterTwo's Foo" and I live in "foo". Master: MasterTwo | foo: my name is "MasterTwo's Foo" and I live in "foo". Also printing $bar and $baz my name is "MasterTwo's Foo" and I live in "foo". my name is "MasterTwo's Foo" and I live in "foo".
上個例子解析:
$bar = new foo('bar'); $m1 = new MasterOne( $bar ); $m2 = new MasterTwo( $bar );
在php4中,要實現如上述的 用一個對象實例去當着另一個對象的屬性時,其等價代碼(即引用調用)相似以下:
class foo{ var $bar; function setBar(&$newBar){ $this->bar =& newBar; } }
5.引用的做用
若是程序比較大,引用同一個對象的變量比較多,而且但願用完該對象後手工清除它,我的建議用 "&" 方式,而後用$var=null的方式清除. 其它時候仍是用php5的默認方式吧. 另外, php5中對於大數組的傳遞,建議用 "&" 方式, 畢竟節省內存空間使用。
6.取消引用
當你 unset 一個引用,只是斷開了變量名和變量內容之間的綁定。這並不意味着變量內容被銷燬了。例如:
<?php $a = 1; $b =& $a; unset ($a); ?>
不會 unset $b,只是 $a。
7.global 引用
當用 global $var 聲明一個變量時實際上創建了一個到全局變量的引用。也就是說和這樣作是相同的:
<?php $var =& $GLOBALS["var"]; ?>
這意味着,例如,unset $var 不會 unset 全局變量。
若是在一個函數內部給一個聲明爲 global 的變量賦於一個引用,該引用只在函數內部可見。能夠經過使用 $GLOBALS 數組避免這一點。
Example 在函數內引用全局變量
<?php $var1 = "Example variable"; $var2 = ""; function global_references($use_globals){ global $var1, $var2; if (!$use_globals) { $var2 =& $var1; // visible only inside the function } else { $GLOBALS["var2"] =& $var1; // visible also in global context } } global_references(false); echo "var2 is set to '$var2'\n"; // var2 is set to '' global_references(true); echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable' ?>
8.$this
在一個對象的方法中,$this 永遠是調用它的對象的引用。
//下面再來個小插曲
php中對於地址的指向(相似指針)功能不是由用戶本身來實現的,是由Zend核心實現的,php中引用採用的是「寫時拷貝」的原理,就是除非發生寫操做,指向同一個地址的變量或者對象是不會被拷貝的。
通俗的講
1:若是有下面的代碼
<?php $a="ABC"; $b=&$a; ?>
其實此時 $a與$b都是指向同一內存地址 而並非$a與$b佔用不一樣的內存
2:若是在上面的代碼基礎上再加上以下代碼
<?php $a="EFG"; ?>
因爲$a與$b所指向的內存的數據要從新寫一次了,此時Zend核心會自動判斷 自動爲$b生產一個$a的數據拷貝,從新申請一塊內存進行存儲
php的引用(就是在變量或者函數、對象等前面加上&符號)是個高級話題,新手多注意,正確的理解php的引用很重要,對性能有較大影響,並且理解錯誤可能致使程序錯誤!
很 多人誤解php中的引用跟C當中的指針同樣,事實上並不是如此,並且很大差異。C語言中的指針除了在數組傳遞過程當中不用顯式申明外,其餘都須要使用*進行定 義,而php中對於地址的指向(相似指針)功能不是由用戶本身來實現的,是由Zend核心實現的,php中引用採用的是「寫時拷貝」的原理,就是除非發生 寫操做,指向同一個地址的變量或者對象是不會被拷貝的,好比下面的代碼:
$a = array('a','c'...'n'); $b = $a;
如 果程序僅執行到這裏,$a和$b是相同的,可是並無像C那樣,$a和$b佔用不一樣的內存空間,而是指向了同一塊內存,這就是php和c的差異,並不須要 寫成$b=&$a才表示$b指向$a的內存,zend就已經幫你實現了引用,而且zend會很是智能的幫你去判斷何時該這樣處理,何時不 該這樣處理。
若是在後面繼續寫以下代碼,增長一個函數,經過引用的方式傳遞參數,並打印輸出數組大小。
function printArray(&$arr){ //引用傳遞 print(count($arr)); } printArray($a);
上面的代碼中,咱們經過引用把$a數組傳入printArray()函數,zend引擎會認爲printArray()可能會致使對$a的改變,此時就會自動爲$b生產一個$a的數據拷貝,從新申請一塊內存進行存儲。這就是前面提到的「寫時拷貝」概念。
若是咱們把上面的代碼改爲下面這樣:
function printArray($arr){ //值傳遞 print(count($arr)); } printArray($a);
上面的代碼直接傳遞$a值到printArray()中,此時並不存在引用傳遞,因此沒有出現寫時拷貝。
你們能夠測試一下上面兩行代碼的執行效率,好比外面加入一個循環1000次,看看運行的耗時,結果會讓你知道不正確使用引用會致使性能降低30%以上。
自我理解:按傳值的話是與函數內的參數無關,至關於局部變量的做用,而按傳址(引用)的話卻與函數內的參數有關,至關於全局變量的做用.而從性能方面來講,看上面分析就夠.