PHP引用(&)各種使用方法執行個體詳解

來源:互聯網
上載者:User

 php的引用(就是在變數或者函數、對象等前面加上&符號),在PHP 中引用的意思是:不同的名字訪問同一個變數內容。與C語言中的指標是有差別的.C語言中的指標裡面儲存的是變數的內容,在記憶體中存放的地址

php的引用(就是在變數或者函數、對象等前面加上&符號),在PHP 中引用的意思是:不同的名字訪問同一個變數內容。與C語言中的指標是有差別的.C語言中的指標裡面儲存的是變數的內容,在記憶體中存放的地址。 1.變數的引用PHP 的引用允許你用兩個變數來指向同一個內容  代碼如下:<?    $a="ABC";    $b =&$a;    echo $a;//這裡輸出:ABC    echo $b;//這裡輸出:ABC    $b="EFG";    echo $a;//這裡$a的值變為EFG 所以輸出EFG    echo $b;//這裡輸出EFG?> 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);的話就會出錯,原因自己去想。注意:上面的“ test($b); ” 中的$b前面不要加 & 符號,但是在函數“call_user_func_array”中,若要引用傳參,就得需要 & 符號,如下代碼所示:  代碼如下:<?phpfunction a(&$b){    $b++;}$c=0;call_user_func_array('a',array(&$c));echo $c;//輸出 1?>3.函數的引用返回先看代碼代碼如下:<?phpfunction &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.<?phpclass 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。自 PHP 5 起,new 自動返回引用,因此在此使用 =& 已經過時了並且會產生 E_STRICT 層級的訊息。在php4中,對象的賦值是個拷貝過程,如:$b=new a,其中new a產生的是一個匿名的a對象執行個體,而此時的$b是對這個匿名對象的拷貝。同理$c=$b,也是對$b內容的一個拷貝。所以在php4中,為了節省記憶體空間,$b=new a 一般會改成引用的模式,即 $b=& new a。 下面再來個 官方 提供的例子:在php5中,你不需要額外添加什麼東西就可到達“對象引用”的功能:  代碼如下:<?phpclass 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 $barn");print( $bar );print("n");print("Now $baz is referenced to $bar and printing $bar and $bazn"); $baz =& $bar;print( $bar );print("n");print("Now Creating MasterOne and Two and passing $bar to both constructorsn"); $m1 = new MasterOne( $bar );$m2 = new MasterTwo( $bar );print( $m1 );print( $m2 );print("n");print("Now changing value of $bar and printing $bar and $bazn"); $bar->setName('baz');print( $bar );print( $baz );print("n");print("Now printing again MasterOne and Twon");print( $m1 );print( $m2 );print("n");print("Now changing MasterTwo's foo name and printing again MasterOne and Twon"); $m2->setFooName( 'MasterTwo's Foo' );print( $m1 );print( $m2 );print("Also printing $bar and $bazn");print( $bar );print( $baz );?>  輸出:  代碼如下:Only Created $bar and printing $barmy name is "bar" and I live in "foo".Now $baz is referenced to $bar and printing $bar and $bazmy name is "bar" and I live in "foo".Now Creating MasterOne and Two and passing $bar to both constructorsMaster: 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 $bazmy name is "baz" and I live in "foo".my name is "baz" and I live in "foo".Now printing again MasterOne and TwoMaster: 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 TwoMaster: 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 $bazmy 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 ); 執行個體對象$m1與$m2中的$bar是對執行個體$bar的引用,而非拷貝,這是php5中,對象引用的特點,也就是說1.$m1或$m2內部,任何對$bar的操作都會影響外部對象執行個體$bar的相關值。2.外部對象執行個體$bar的改變也會影響$m1和$m2內部的$bar的引用相關值。 在php4中,要實現如上述的 用一個對象執行個體去當著另外一個對象的屬性時,其等價代碼(即引用調用)類似如下:  代碼如下:class foo{   var $bar;   function setBar(&$newBar){      $this->bar =& newBar;   }} 5.引用的作用如果程式比較大,引用同一個對象的變數比較多,並且希望用完該對象後手工清除它,個人建議用 "&" 方式,然後用$var=null的方式清除. 其它時候還是用php5的預設吧. 另外, php5中對於大數組的傳遞,建議用 "&" 方式, 畢竟節省記憶體空間使用。6.取值 (Dereference)當你 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'?> 把 global $var; 當成是 $var =& $GLOBALS['var']; 的簡寫。從而將其它引用賦給 $var 只改變了本地變數的引用。 8.$this在一個對象的方法中,$this 永遠是調用它的對象的引用。//下面再來個小插曲php中對於地址的指向(類似指標)功能不是由使用者自己來實現的,是由Zend核心實現的,php中引用採用的是“寫時拷貝”的原理,就是除非發生寫操作,指向同一個地址的變數或者對象是不會被拷貝的。通俗的講1:如果有下面的代碼[code]<?    $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%以上。自我理解:按傳值的話是與函數內的參數無關,相當於局部變數的作用,而按傳址(引用)的話卻與函數內的參數有關,相當於全域變數的作用.而從效能方面來說,看上面分析就夠.. 
相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

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

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