PHP的引用,你知道多少

真的是變懶了,一個月一篇的節湊都很難保證了。php

最近面試他人的過程當中,問了一些關於PHP引用的知識,發現不少同窗對這方面知之甚少,還有不少工做中基本沒有使用過。甚至有人告訴我要少用引用,引用會帶來一些詭異的問題。我內心默默說,避免詭異的問題是要去理解引用而不是少用引用。今天一塊兒來解析解析。面試

場景假設

先從一個引用的所謂詭異問題開始。假設咱們有這個場景:咱們從數據庫中讀取了一組訂單數據,須要把訂單的每條數據單獨作些處理。數據庫

$orders = [
    ['orderid' => '123', 'total_fee' => 10, 'name' => 'zhangsan'],
    ['orderid' => '456', 'total_fee' => 17, 'name' => 'lisi'],
    ['orderid' => '789', 'total_fee' => 14, 'name' => 'wangwu'],
];

foreach ($orders as &$item) {
    // 對訂單作了些什麼處理
}

// 有了一些其它操做

$result = [];// 須要返回的結果
foreach ($orders as $item) {// 從新映射名字
    $result[] = [
        'order_id' => $item['orderid'],
        'amount' => $item['total_fee'],
    ];
}

複製代碼

上面的程序會輸出以下結果:數組

var_dump($result);

array(3) {
  [0]=>
  array(2) {
    ["order_id"]=>
    string(3) "123"
    ["total_fee"]=>
    int(10)
  }
  [1]=>
  array(2) {
    ["order_id"]=>
    string(3) "456"
    ["total_fee"]=>
    int(17)
  }
  [2]=>
  array(2) {
    ["order_id"]=>
    string(3) "456"
    ["total_fee"]=>
    int(17)
  }
}
複製代碼

這就是常常遇到的一種所謂的詭異問題,先用引用循環處理數據,後面又用了與引用相同的臨時變量繼續處理數據。這裏就是:$item。不少同窗說預防這種問題,就要少用引用。這種態度太消極了,引用在不少地方帶來了代碼書寫的簡潔,而且針對大數組使用引用可以節省大量的內存。框架

詭異問題解析

如今咱們來分析下上面問題出現的緣由。先來看引用的定義網站

引用意味着用不一樣的名字訪問同一個變量內容。spa

那麼在這部分代碼中code

foreach ($orders as &$item) {
    // 對訂單作了些什麼處理
}
複製代碼

$item 最後跟 $orders[2] 指向了同一個變量內容。而且在 foreach 循環完後,$item 並無被銷燬,所以在後續若是同名的話,會繼續生效。圖示以下: cdn

image

那麼再接下來的的另外一個循環中。blog

foreach ($orders as $item) {// 從新映射名字
    $result[] = [
        'order_id' => $item['orderid'],
        'amount' => $item['total_fee'],
    ];
}
複製代碼

每當 $orders 把變量賦值給 $item 的時候,都同時改變了 $orders[2] 的值。所以纔會出現上面詭異的狀況。我來逐步給你們演示下:

  • 第一次循環 $orders[0]$item 指向 orderid=123 的訂單,因爲 $item$orders[2] 的引用,此時致使 $orders[2] 也指向了 orderid=123 的訂單;
  • 第二次循環 $orders[1], $item 指向 orderid=456 的訂單,所以 $orders[2] 也指向了 orderid=456
  • 第三次循環 $orders[2]的時候,明顯其值已經變成了 orderid=456 的訂單。

經過上面的分析,我相信你們對引用所謂的詭異有了瞭解。那麼又該如何避免這種狀況出現呢?其實很簡單,每次使用完引用後,記得 unset 調引用。在後面即可毫無顧忌的繼續使用了。具體到本例子就是:

foreach ($orders as &$item) {
    // 對訂單作了些什麼處理
}
unset($item);

// 有了一些其它操做

foreach ($orders as $item) {// 從新映射名字
}
複製代碼

引用的妙用

前面我說過,引用能夠寫出簡潔的代碼。無限級分類的使用即是一個使用場景。好比說咱們有個分類的數據:

$catList = [
    '1' => ['id' => 1, 'name' => '顏色', 'parent_id' => 0],
    '2' => ['id' => 2, 'name' => '規格', 'parent_id' => 0],
    '3' => ['id' => 3, 'name' => '白色', 'parent_id' => 1],
    '4' => ['id' => 4, 'name' => '黑色', 'parent_id' => 1],
    '5' => ['id' => 5, 'name' => '大', 'parent_id' => 2],
    '6' => ['id' => 6, 'name' => '小', 'parent_id' => 2],
    '7' => ['id' => 7, 'name' => '黃色', 'parent_id' => 1],
];
複製代碼

若是我想獲得下面這種形式

$result = [
    ['id' => 1, 'name' => '顏色', 'children' => [
        ['id' => 3, 'name' => '白色'],
        ['id' => 4, 'name' => '黑色'],
        ['id' => 7, 'name' => '黃色']
    ]],
    ['id' => 2, 'name' => '規格', 'children' => [
        ['id' => 5, 'name' => '大'],
        ['id' => 6, 'name' => '小']
    ]]
];
複製代碼

若是使用引用,能夠很是簡單的得出結果。

$treeData = [];// 保存結果
foreach ($catList as $item) {
    if (isset($catList[$item['parent_id']]) && ! empty($catList[$item['parent_id']])) {// 確定是子分類
        $catList[$item['parent_id']]['children'][] = &$catList[$item['id']];
    } else {// 確定是一級分類
        $treeData[] = &$catList[$item['id']];
    }
}

複製代碼

你們能夠試試不用引用的方式,把無限級實現出來試試,比較下代碼。


年末了。沒錢給你們發紅包,給你們推薦一家上海的好公司。爲你們跳槽助力。

image
image

公司網站:https://www.yimishiji.com/

手機網站:https://m.yimishiji.com/

公司目前正在招聘高級PHP工程師,要求:

  • 2-5年的PHP開發經驗;
  • 本科學歷;
  • 至少熟悉Laravel、Yii2框架中的一種;
  • 有電商、生鮮相關的經驗加分;
  • 有博客、GitHub的加分。

待遇優厚:五險一金;每日內購零農殘、有機食材水果;薪資15k-30k。

公司使用的是PHP7語法,對新技術是保持激進的態度。對於上海的小夥伴或者想去上海的小夥伴,強烈建議去看看。

  • 公司地址:上海市長寧區天山西路789號中山國際廣場B座一米市集
  • CTO郵箱:alex.chang@yimishiji.com
相關文章
相關標籤/搜索