PHP引用(&)各種使用方法實例詳解
來源:易賢網(wǎng) 閱讀:846 次 日期:2014-08-22 09:57:16
溫馨提示:易賢網(wǎng)小編為您整理了“PHP引用(&)各種使用方法實例詳解”,方便廣大網(wǎng)友查閱!

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

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

1.變量的引用

PHP 的引用允許你用兩個變量來指向同一個內(nèi)容

代碼如下:<?

$a="ABC";

$b =&$a;

echo $a;//這里輸出:ABC

echo $b;//這里輸出:ABC

$b="EFG";

echo $a;//這里$a的值變?yōu)镋FG 所以輸出EFG

echo $b;//這里輸出EFG

?>

2.函數(shù)的引用傳遞(傳址調(diào)用)

傳址調(diào)用我就不多說了 下面直接給出代碼

代碼如下:<?php

function test(&$a)

{

$a=$a+100;

}

$b=1;

echo $b;//輸出1

test($b); //這里$b傳遞給函數(shù)的其實是$b的變量內(nèi)容所處的內(nèi)存地址,通過在函數(shù)里改變$a的值 就可以改變$b的值了

echo "<br>";

echo $b;//輸出101

?>

要注意的是,在這里test(1);的話就會出錯,原因自己去想。

注意:上面的“ test($b); ” 中的$b前面不要加 & 符號,但是在函數(shù)“call_user_func_array”中,若要引用傳參,就得需要 & 符號,如下代碼所示:

代碼如下:<?php

function a(&$b){

$b++;

}

$c=0;

call_user_func_array('a',array(&$c));

echo $c;

//輸出 1

?>

3.函數(shù)的引用返回

先看代碼

代碼如下:<?php

function &test()

{

static $b=0;//申明一個靜態(tài)變量

$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();得到的其實不是函數(shù)的引用返回,這跟普通的函數(shù)調(diào)用沒有區(qū)別 至于原因: 這是PHP的規(guī)定

PHP規(guī)定通過$a=&test(); 方式得到的才是函數(shù)的引用返回

至于什么是引用返回呢(PHP手冊上說:引用返回用在當想用函數(shù)找到引用應(yīng)該被綁定在哪一個變量上面時。) 這句狗屁話 害我半天沒看懂

用上面的例子來解釋就是

$a=test()方式調(diào)用函數(shù),只是將函數(shù)的值賦給$a而已, 而$a做任何改變 都不會影響到函數(shù)中的$b

而通過$a=&test()方式調(diào)用函數(shù)呢, 他的作用是 將return $b中的 $b變量的內(nèi)存地址與$a變量的內(nèi)存地址 指向了同一個地方

即產(chǎn)生了相當于這樣的效果($a=&$b;) 所以改變$a的值 也同時改變了$b的值 所以在執(zhí)行了

$a=&test();

$a=5;

以后,$b的值變?yōu)榱?

這里是為了讓大家理解函數(shù)的引用返回才使用靜態(tài)變量的,其實函數(shù)的引用返回多用在對象中

另附一個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中默認就是通過引用來調(diào)用對象, 但有時你可能想建立一個對象的副本,并希望原來的對象的改變不影響到副本 . 為了這樣的目的,PHP5定義了一個特殊的方法,稱為__clone。

自 PHP 5 起,new 自動返回引用,因此在此使用 =& 已經(jīng)過時了并且會產(chǎn)生 E_STRICT 級別的消息。

在php4中,對象的賦值是個拷貝過程,

如:$b=new a,其中new a產(chǎn)生的是一個匿名的a對象實例,而此時的$b是對這個匿名對象的拷貝。同理$c=$b,也是對$b內(nèi)容的一個拷貝。所以在php4中,為了節(jié)省內(nèi)存空間,$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 $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 $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 );

實例對象$m1與$m2中的$bar是對實例$bar的引用,而非拷貝,這是php5中,對象引用的特點,也就是說

1.$m1或$m2內(nèi)部,任何對$bar的操作都會影響外部對象實例$bar的相關(guān)值。

2.外部對象實例$bar的改變也會影響$m1和$m2內(nèi)部的$bar的引用相關(guān)值。

在php4中,要實現(xiàn)如上述的 用一個對象實例去當著另外一個對象的屬性時,其等價代碼(即引用調(diào)用)類似如下:

代碼如下:class foo{

var $bar;

function setBar(&$newBar){

$this->bar =& newBar;

}

}

5.引用的作用

如果程序比較大,引用同一個對象的變量比較多,并且希望用完該對象后手工清除它,個人建議用 "&" 方式,然后用$var=null的方式清除. 其它時候還是用php5的默認方式吧. 另外, php5中對于大數(shù)組的傳遞,建議用 "&" 方式, 畢竟節(jié)省內(nèi)存空間使用。

6.取消引用

當你 unset 一個引用,只是斷開了變量名和變量內(nèi)容之間的綁定。這并不意味著變量內(nèi)容被銷毀了。例如:

代碼如下:

<?php

$a = 1;

$b =& $a;

unset ($a);

?>

不會 unset $b,只是 $a。

7.global 引用

當用 global $var 聲明一個變量時實際上建立了一個到全局變量的引用。也就是說和這樣做是相同的:

<?php

$var =& $GLOBALS["var"];

?>

這意味著,例如,unset $var 不會 unset 全局變量。

如果在一個函數(shù)內(nèi)部給一個聲明為 global 的變量賦于一個引用,該引用只在函數(shù)內(nèi)部可見。可以通過使用 $GLOBALS 數(shù)組避免這一點。

Example 在函數(shù)內(nèi)引用全局變量

代碼如下:<?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 永遠是調(diào)用它的對象的引用。

//下面再來個小插曲

php中對于地址的指向(類似指針)功能不是由用戶自己來實現(xiàn)的,是由Zend核心實現(xiàn)的,php中引用采用的是“寫時拷貝”的原理,就是除非發(fā)生寫操作,指向同一個地址的變量或者對象是不會被拷貝的。

通俗的講

1:如果有下面的代碼

[code]<?

$a="ABC";

$b=&$a;

?>

其實此時 $a與$b都是指向同一內(nèi)存地址 而并不是$a與$b占用不同的內(nèi)存

2:如果在上面的代碼基礎(chǔ)上再加上如下代碼

代碼如下:<?php

$a="EFG";

?>

由于$a與$b所指向的內(nèi)存的數(shù)據(jù)要重新寫一次了,此時Zend核心會自動判斷 自動為$b生產(chǎn)一個$a的數(shù)據(jù)拷貝,重新申請一塊內(nèi)存進行存儲

php的引用(就是在變量或者函數(shù)、對象等前面加上&符號)是個高級話題,新手多注意,正確的理解php的引用很重要,對性能有較大影響,而且理解錯誤可能導(dǎo)致程序錯誤!

很 多人誤解php中的引用跟C當中的指針一樣,事實上并非如此,而且很大差別。C語言中的指針除了在數(shù)組傳遞過程中不用顯式申明外,其他都需要使用*進行定 義,而php中對于地址的指向(類似指針)功能不是由用戶自己來實現(xiàn)的,是由Zend核心實現(xiàn)的,php中引用采用的是“寫時拷貝”的原理,就是除非發(fā)生 寫操作,指向同一個地址的變量或者對象是不會被拷貝的,比如下面的代碼:

代碼如下:$a = array('a','c'...'n');

$b = $a;

如果程序僅執(zhí)行到這里,$a和$b是相同的,但是并沒有像C那樣,$a和$b占用不同的內(nèi)存空間,而是指向了同一塊內(nèi)存,這就是php和c的差別,并不需要 寫成$b=&$a才表示$b指向$a的內(nèi)存,zend就已經(jīng)幫你實現(xiàn)了引用,并且zend會非常智能的幫你去判斷什么時候該這樣處理,什么時候不 該這樣處理。

如果在后面繼續(xù)寫如下代碼,增加一個函數(shù),通過引用的方式傳遞參數(shù),并打印輸出數(shù)組大小。

代碼如下:function printArray(&$arr) //引用傳遞

{

print(count($arr));

}

printArray($a);

上面的代碼中,我們通過引用把$a數(shù)組傳入printArray()函數(shù),zend引擎會認為printArray()可能會導(dǎo)致對$a的改變,此時就會自動為$b生產(chǎn)一個$a的數(shù)據(jù)拷貝,重新申請一塊內(nèi)存進行存儲。這就是前面提到的“寫時拷貝”概念。

如果我們把上面的代碼改成下面這樣:

代碼如下:function printArray($arr) //值傳遞

{

print(count($arr));

}

printArray($a);

上面的代碼直接傳遞$a值到printArray()中,此時并不存在引用傳遞,所以沒有出現(xiàn)寫時拷貝。

大家可以測試一下上面兩行代碼的執(zhí)行效率,比如外面加入一個循環(huán)1000次,看看運行的耗時,結(jié)果會讓你知道不正確使用引用會導(dǎo)致性能下降30%以上。

自我理解:按傳值的話是與函數(shù)內(nèi)的參數(shù)無關(guān),相當于局部變量的作用,而按傳址(引用)的話卻與函數(shù)內(nèi)的參數(shù)有關(guān),相當于全局變量的作用.而從性能方面來說,看上面分析就夠..

更多信息請查看IT技術(shù)專欄

更多信息請查看網(wǎng)絡(luò)編程
易賢網(wǎng)手機網(wǎng)站地址:PHP引用(&)各種使用方法實例詳解

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機號
  • 驗證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 新媒體/短視頻平臺 | 手機站點 | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:1093837350(9:00—18:00)版權(quán)所有:易賢網(wǎng)