日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > 謹慎使用PHP的引用類型詳解

謹慎使用PHP的引用類型詳解

來源:程序員人生   發布時間:2014-03-25 17:27:51 閱讀次數:4267次

引用類型(Reference)在許多計算機語言中都被使用,而且是作為一個非常強大而實用的特性存在,它有類似指針(Pointer)的實現,卻又有不同于指針的表現。

例如C++的引用,可以讓不同變量指向同一個對象,同時又保有直接使用dot來獲取對象成員,不用繁瑣的使用dereference運算符(*)和Pointer to Member運算符(->),Java和C#中就直接以引用為主要類型,盡量讓開發人員避免使用指針。

PHP中也引入了引用類型,在對對象賦值傳遞上,基本可視為是同于Java/C#的引用傳遞(具體請見Objects and references),但同時又支持在基礎類型上通過引用運算符(&)來獲得內容的引用。不過在實際的使用中,PHP的引用類型因為整個PHP設計結構而存在著許多的問題,使得在程序出現非預計的結果。

引用變量可被賦予新的引用

在C++中,引用類型的變量只能在其定義時被賦予引用值,所以我們只要追蹤到變量的定義處就可以知道變量是在操作哪個內容。

但是PHP不同,PHP里模糊了變量的定義,可以不定義就使用的變量。所以可以讓變量被多次賦予引用值,代碼如下:

$x = 21;$y = 7;$z = &$x;$z = &$y;

var_dump($x,$y,$z);初次看起來,讓人的感覺是$z變成了對$x的引用,然后讓$z的內容變成了對$y的引用,也就是說$x和$z都成對$y的引用,但是實際輸出結果是:

int(21),int(7),int(7)

從結果上看出,$x保持不變,只是$z被改變成了對$y的引用,相當于先unset了$z變量然后賦予了新值。

$z = &$x;unset($z);

$z = &$y;這其實是比較合理邏輯,就比如下邊的代碼,我們并不是得到類似于“指向指針的指針(Pointer point to a Pointer)”那樣的“引用引用的引用(Reference refer to a Referenece)”,只是多個引用到同一塊內容的引用變量。

$x = 21;$y = &$x;$z = &$y

引用數組元素會讓該元素變成引用類型,對于變量上取引用,并不會造成原變量類型的改變,但是如果取的是數組中的元素,卻會讓該元素也變成引用類型。

在看問題代碼前,首先要指出的就是說PHP的數組賦值是copy而非引用,賦值過程會創建新的數組賦予被賦值的變量,在新變量上的數組操作并不會影響到原數組變量中的內容,代碼如下:

  1. $a = array(21, 7); 
  2. $b = $a
  3. $b[0] = 7; 
  4. var_dump($a); 
  5. echo '<br/>'
  6. var_dump($b); 
  7. //Output: 
  8. //array(2) { [0]=> int(21) [1]=> int(7) }  
  9. //array(2) { [0]=> int(7) [1]=> int(7) } 

下邊我們再來看看如果引用數組中的元素,會有什么異常。

  1. $a = array(21, 7); 
  2. $c = & $a[0]; 
  3. $b = $a
  4. $b[0]= "21"
  5. $b[1]= "7"
  6. var_dump($a); 
  7. echo '<br/>'
  8. var_dump($b); 
  9. echo '<br/>'
  10. var_dump($c); 
  11. echo '<br/>'
  12. // Output: 
  13. // array(2) { [0]=> &string(2) "21" [1]=> int(7) }  
  14. // array(2) { [0]=> &string(2) "21" [1]=> string(1) "7" }  
  15. // string(2) "21" 

代碼中$b跟之前的只是簡單的賦值,只是在之前多了一部取第一個元素的引用,但理應還是拷貝了一個新的數組。可是結果卻是對$b的修改,同時也改變了$a的第一個元素,而第二個元素沒有影響。

從輸出中我們還看到了一個不尋常的地方,就是數組第一個元素的類型多一個‘&’符號。而這個正是取引用運算符。也就是說數組的第一個元素已經變成了引用類型。所以賦值時也是引用拷貝,而非值拷貝。

這個問題十分奇怪,在開發中也造成了許多不必要的困擾,原本以為拷貝出來的數組并沒有跟原數組有關聯,但是就因為這意外出現的引用類型,讓我在操作時也影響到了原數組。

我也不清楚這算是PHP中的bug,還是有意如此設計。在網上找了很久也沒有對該方便的相關解釋,只有Float Middle的《PHP: References To Array Elements Are Risky》和 Symmetric Designs的《Problems w/accessing a PHP array by reference》里有談到這個,但是也沒有講原因。

之后又在PHP的Bug Report中看到幾篇有聯系的報告(Bug6417, Bug7412, Bug15025, Bug20993)。有些說這是個Bug,而且已經在后邊的版本被修復。具體我也沒有明白,只能避免在數組上使用引用。

更有趣的事情是,如果unset那些引用,只留下一個,那么數組元素又會變成不含有引用的正常類型,代碼如下:

  1. unset($b); 
  2. unset($c); 
  3. var_dump($a); 
  4. // Output: 
  5. //array(2) { [0]=> string(2) "21" [1]=> int(7) } 

避免使用PHP的引用

這個其實這是PHP Array Manual里面提到的要注意的地方,最常發生在foreach的之中,希望通過引用來改變遠數組的值(可參見該篇文章)。

其實想通過使用foreach配合引用來改變數組元素的值,主要是因為PHP的數組是Associative Array,這種數組“不定長度,索引可以不連續,可同時用字符串和整數當索引”,所以我們無法用for循環簡單增加整數索引。

當然我們可以像下邊的代碼那樣通過$key直接對數組元素改變值,但是這可能存在一定的效率問題,代碼如下:

  1. foreach ($array_var as $key => $value
  2. $array_var [$key] = $newValue

另一個常用的引用的地方是在函數調用中使用引用傳遞參數,其主要原因是希望通過這種方法讓函數實現返回多個返回值,比如我們希望用一個表示指示函數是否在執行中出現error而導致返回值是無效的。

但是因為PHP的函數是可以返回不同的類型的,所以并不需要傳入引用參數來作為表示,即使真的需要多個返回值,也可以通過返回“以字符串為主鍵的數組”作為解決方案,只不過可能需要在文檔中指出每個元素都是對應那個結果。

有一個比較好操作方式,應該是每當引用變量不再需要使用時,就即時對該變量使用unset讓它切換與內容之間的聯系。而且即使該變量不是引用類型,我們確認它不再被使用,對它調用unset也不會有什么問題。至少保證在之后對該變量重新賦值時,并不會影響到之前的結果。

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 精品久草| 久久aaa| 97在线视频免费 | 国产欧美一区二区精品性色 | www.超碰在线 | 日韩精品久久 | 爱爱的网站 | 高清一区二区 | 黄色在线片| 日日干夜夜干 | 欧美一区二区三区在线看 | 一区二区三区四区五区视频 | 日韩毛片一区 | 美女视频久久久 | 欧美日本韩国一区二区三区 | 久久久精选 | 牲高潮99爽久久久久777 | 中文字幕 欧美 日韩 | 尤物九九久久国产精品的特点 | 国产精品亚洲一区二区三区在线 | 日本中文字幕一区 | 91看电视 | 精品一区二区三区四区 | 成人欧美一区二区三区视频网页 | 国产精品三级 | 久久国产一区 | 视频一区二区国产 | 精品美女久久久久久免费 | 午夜美女网站 | 经典一区二区 | 午夜精品一区二区三区在线播放 | 精品在线播放 | 黄色一级免费 | 亚洲日本综合 | 久久久国产精品入口麻豆 | 免费黄色a级毛片 | 国产又黄又爽又色的免费视频 | 午夜精品久久久久99蜜 | 久久久久免费 | 99精品欧美一区二区蜜桃免费 | 国产精华一区二区三区 |