|
引用類型(Reference)在許多計算機(jī)語言中都被使用,而且是作為一個非常強(qiáng)大而實用的特性存在。它有類似指針(Pointer)的實現(xiàn),卻又有不同于指針的表現(xiàn)。例如C++的引用,可以讓不同變量指向同一個對象,同時又保有直接使用dot來獲取對象成員,不用繁瑣的使用dereference運(yùn)算符(*)和Pointer to Member運(yùn)算符(->)。Java和C#中就直接以引用為主要類型,盡量讓開發(fā)人員避免使用指針。
php中也引入了引用類型,在對對象賦值傳遞上,基本可視為是同于Java/C#的引用傳遞(具體請見Objects and references)。但同時又支持在基礎(chǔ)類型上通過引用運(yùn)算符(&)來獲得內(nèi)容的引用。不過在實際的使用中,php的引用類型因為整個php設(shè)計結(jié)構(gòu)而存在著許多的問題,使得在程序出現(xiàn)非預(yù)計的結(jié)果。
引用變量可被賦予新的引用
在C++中,引用類型的變量只能在其定義時被賦予引用值,所以我們只要追蹤到變量的定義處就可以知道變量是在操作哪個內(nèi)容。
但是php不同,php里模糊了變量的定義,可以不定義就使用的變量。所以可以讓變量被多次賦予引用值。
復(fù)制代碼 代碼如下:
$x = 21;
$y = 7;
$z = &$x;
$z = &$y;
var_dump($x,$y,$z);
初次看起來,讓人的感覺是$z變成了對$x的引用,然后讓$z的內(nèi)容變成了對$y的引用,也就是說$x和$z都成對$y的引用。但是實際輸出結(jié)果是:
復(fù)制代碼 代碼如下:
int(21)
int(7)
int(7)
從結(jié)果上看出,$x保持不變,只是$z被改變成了對$y的引用。相當(dāng)于先unset了$z變量然后賦予了新值。
復(fù)制代碼 代碼如下:
$z = &$x;
unset($z);
$z = &$y;
這其實是比較合理邏輯,就比如下邊的代碼,我們并不是得到類似于“指向指針的指針(Pointer point to a Pointer)”那樣的“引用引用的引用(Reference refer to a Referenece)”,只是多個引用到同一塊內(nèi)容的引用變量。
復(fù)制代碼 代碼如下:
$x = 21;
$y = &$x;
$z = &$y
引用數(shù)組元素會讓該元素變成引用類型
對于變量上取引用,并不會造成原變量類型的改變,但是如果取的是數(shù)組中的元素,卻會讓該元素也變成引用類型。
在看問題代碼前,首先要指出的是:
Array assignment always involves value copying. Use the reference operator to copy an array by reference.
也就是說php的數(shù)組賦值是copy而非引用,賦值過程會創(chuàng)建新的數(shù)組賦予被賦值的變量。在新變量上的數(shù)組操作并不會影響到原數(shù)組變量中的內(nèi)容。
復(fù)制代碼 代碼如下:
$a = array(21, 7);
$b = $a;
$b[0] = 7;
var_dump($a);
echo '<br/>';
var_dump($b);
//Output:
//array(2) { [0]=> int(21) [1]=> int(7) }
//array(2) { [0]=> int(7) [1]=> int(7) }
下邊我們再來看看如果引用數(shù)組中的元素,會有什么異常。
復(fù)制代碼 代碼如下:
$a = array(21, 7);
$c = & $a[0];
$b = $a;
$b[0]= "21";
$b[1]= "7";
var_dump($a);
echo '<br/>';
var_dump($b);
echo '<br/>';
var_dump($c);
echo '<br/>';
// Output:
// array(2) { [0]=> &string(2) "21" [1]=> int(7) }
// array(2) { [0]=> &string(2) "21" [1]=> string(1) "7" }
// string(2) "21"
代碼中$b跟之前的只是簡單的賦值,只是在之前多了一部取第一個元素的引用,但理應(yīng)還是拷貝了一個新的數(shù)組。可是結(jié)果卻是對$b的修改,同時也改變了$a的第一個元素,而第二個元素沒有影響。
從輸出中我們還看到了一個不尋常的地方,就是數(shù)組第一個元素的類型多一個‘&'符號。而這個正是取引用運(yùn)算符。也就是說數(shù)組的第一個元素已經(jīng)變成了引用類型。所以賦值時也是引用拷貝,而非值拷貝。
這個問題十分奇怪,在開發(fā)中也造成了許多不必要的困擾,原本以為拷貝出來的數(shù)組并沒有跟原數(shù)組有關(guān)聯(lián),但是就因為這意外出現(xiàn)的引用類型,讓我在操作時也影響到了原數(shù)組。
我也不清楚這算是php中的bug,還是有意如此設(shè)計。在網(wǎng)上找了很久也沒有對該方便的相關(guān)解釋,只有Float Middle的《php: References To Array Elements Are Risky》和 Symmetric Designs的《Problems w/accessing a php array by reference》里有談到這個,但是也沒有講原因。
之后又在php的Bug Report中看到幾篇有聯(lián)系的報告(Bug6417, Bug7412, Bug15025, Bug20993)。有些說這是個Bug,而且已經(jīng)在后邊的版本被修復(fù)。具體我也沒有明白,只能避免在數(shù)組上使用引用。
更有趣的事情是,如果unset那些引用,只留下一個,那么數(shù)組元素又會變成不含有引用的正常類型。
復(fù)制代碼 代碼如下:
unset($b);
unset($c);
var_dump($a);
// Output:
//array(2) { [0]=> string(2) "21" [1]=> int(7) }
避免使用php的引用
這個其實這是php Array Manual里面提到的要注意的地方,最常發(fā)生在foreach的之中,希望通過引用來改變遠(yuǎn)數(shù)組的值(可參見該篇文章)。
其實想通過使用foreach配合引用來改變數(shù)組元素的值,主要是因為php的數(shù)組是Associative Array,這種數(shù)組“不定長度,索引可以不連續(xù),可同時用字符串和整數(shù)當(dāng)索引”,所以我們無法用for循環(huán)簡單增加整數(shù)索引。
當(dāng)然我們可以像下邊的代碼那樣通過$key直接對數(shù)組元素改變值,但是這可能存在一定的效率問題。
復(fù)制代碼 代碼如下:
foreach ($array_var as $key => $value)
$array_var [$key] = $newValue;
另一個常用的引用的地方是在函數(shù)調(diào)用中使用引用傳遞參數(shù)。其主要原因是希望通過這種方法讓函數(shù)實現(xiàn)返回多個返回值。比如我們希望用一個表示指示函數(shù)是否在執(zhí)行中出現(xiàn)error而導(dǎo)致返回值是無效的。
但是因為php的函數(shù)是可以返回不同的類型的,所以并不需要傳入引用參數(shù)來作為表示。即使真的需要多個返回值,也可以通過返回“以字符串為主鍵的數(shù)組”作為解決方案,只不過可能需要在文檔中指出每個元素都是對應(yīng)那個結(jié)果。
有一個比較好操作方式,應(yīng)該是每當(dāng)引用變量不再需要使用時,就即時對該變量使用unset讓它切換與內(nèi)容之間的聯(lián)系。而且即使該變量不是引用類型,我們確認(rèn)它不再被使用,對它調(diào)用unset也不會有什么問題。至少保證在之后對該變量重新賦值時,并不會影響到之前的結(jié)果。
- Problems w/accessing a php array by reference - Symmetric Designs
- php: References To Array Elements Are Risky 主站蜘蛛池模板: jizzzz亚洲丰满xxxx | 日韩精品熟女一区二区三区中文 | 久久国产精品免费A片蜜芽 久久国产精品萌白酱免费 久久国产精品麻豆AV影视 | 99久久蜜臀AV免费看蛮 | 99re久久热免费视频 | 亚洲日韩欧美国产专区 | 久久久久久久久久毛片精品美女 | 乌克兰16~18sex | 被老头下药玩好爽 | 国产黄A片在线观看永久免费麻豆 | 久久精品无码人妻无码AV蜜臀 | 佐山爱痴汉theav | 欧洲兽交另类AVXXX | 欧美不卡一区二区三区 | 一本之道高清在线观看免费 | 色综合伊人色综合网站 | 欧美成人免费一区二区三区不卡 | 国产中文在线观看 | 99视频免费看 | 日韩精品a在线视频 | 欧美牲交A欧美牲交 | 国产对白精品刺激一区二区 | 97人摸人人澡人人人超一碰 | xfplay 无码专区 亚洲 | 中文字幕在线视频免费观看 | 人人听力网mp3下载 人人舔人人爱 | 成人无码国产AV免费看直播 | 男人J放进女人屁股免费观看 | 麻豆第一区MV免费观看网站 | 日韩在线中文字幕无码 | 色迷迷导航| 18禁国产精品久久久久久麻豆 | 亚洲精品久久久久AV无码 | 在线播放免费人成毛片视频 | 国偷自产视频一区二区久 | 超碰97人人做人人爱少妇 | 依恋影院在线观看 | 99热在线视频这里只精品 | 亚洲精品久久久久一区二区三 | 超碰97人人做人人爱网站 | 人人碰在线视频 |