国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > 建站經驗 > 正文

php引用(&)詳解及注意事項

2024-04-25 20:36:16
字體:
來源:轉載
供稿:網友

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”中,若要引用傳參,就得需要 & 符號,如下代碼所示:

<?php

function a(&$b) {

$b++;

}

$c = 0;

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

echo $c; //輸出 1

?>

3.函數的引用返回

先看代碼:

<?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官方例子:

<?php

// This is the way how we use pointer to access variable inside the class.

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。

自 PHP 5 起,new 自動返回引用,因此在此使用 =& 已經過時了并且會產生 E_STRICT 級別的消息。在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__ . '".' . " ";

}

function setName($str) {

$this->name = $str;

}

}

class MasterOne {

protected $foo;

function __construct($f) {

$this->foo = $f;

}

function __toString() {

return 'Master: ' . __CLASS__ . ' | foo: ' . $this->foo . " ";

}

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 . " ";

}

function setFooName($str) {

$this->foo->setName($str);

}

}

$bar = new foo('bar');

print(" ");

print("Only Created $bar and printing $bar ");

print($bar);

print(" ");

print("Now $baz is referenced to $bar and printing $bar and $baz ");

$baz = &$bar;

print($bar);

print(" ");

print("Now Creating MasterOne and Two and passing $bar to both constructors");

$m1 = new MasterOne($bar);

$m2 = new MasterTwo($bar);

print($m1);

print($m2);

print(" ");

print("Now changing value of $bar and printing $bar and $baz");

$bar->setName('baz');

print($bar);

print($baz);

print(" ");

print("Now printing again MasterOne and Two");

print($m1);

print($m2);

print(" ");

print("Now changing MasterTwo's foo name and printing again MasterOne and Two");

$m2->setFooName('MasterTwo/'s Foo');

print($m1);

print($m2);

print("Also printing $bar and $baz");

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);

實例對象$m1與$m2中的$bar是對實例$bar的引用,而非拷貝,這是PHP5中,對象引用的特點,也就是說
$m1或$m2內部,任何對$bar的操作都會影響外部對象實例$bar的相關值。

外部對象實例$bar的改變也會影響$m1和$m2內部的$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'

"; // var2 is set to ''

global_references(true);

echo "var2 is set to '$var2'

"; // var2 is set to 'Example variable'

?>

把 global $var; 當成是 $var = &$GLOBALS['var']; 的簡寫。從而將其它引用賦給 $var 只改變了本地變量的引用。

8.$this

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

//下面再來個小插曲

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

通俗的講

1:如果有下面的代碼

<?

$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%以上。

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

 

 

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 泗阳县| 五寨县| 辛集市| 沙洋县| 长沙县| 安阳市| 南漳县| 永仁县| 新和县| 海门市| 囊谦县| 新宁县| 天水市| 广宁县| 黄平县| 盐池县| 咸阳市| 噶尔县| 三江| 改则县| 余干县| 新巴尔虎右旗| 简阳市| 博罗县| 射洪县| 友谊县| 崇信县| 如皋市| 德化县| 稻城县| 甘孜县| 娄底市| 常德市| 会理县| 古丈县| 司法| 乌海市| 廉江市| 玉门市| 略阳县| 谢通门县|