摘要:引用本身概念好理解性能也很好但是用好它還是存在著一定的門檻不太好寫。寫本文的起因是這幾天碰到非常好的一個解決方案,讓我重新理解了引用。如果下面的代碼,你看完就能理解了,說明你引用真是學(xué)到家了你也可以直接跳過本文哈。
起因:
日常開發(fā)中,我們會碰到構(gòu)造樹的需求,通過id,pid的關(guān)系去構(gòu)建一個樹結(jié)構(gòu),然后對樹進(jìn)行遍歷等操作。其實(shí)現(xiàn)方式分為兩種: 1. 遞歸, 2. 引用
而這兩個方法的優(yōu)缺點(diǎn)也很明顯。
遞歸實(shí)現(xiàn)起來較容易,但是隨著數(shù)著數(shù)據(jù)量的增大,其性能很低。
引用本身概念好理解,性能也很好,但是用好它還是存在著一定的門檻,不太好寫。
寫本文的起因是,這幾天碰到非常好的一個解決方案,讓我重新理解了引用。通過本文,總結(jié)下自己的學(xué)習(xí)成果.ok,那直接上代碼了。
Practise如果下面的代碼,你看完就能理解了,說明你引用真是學(xué)到家了, 你也可以直接跳過本文哈~。
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { $tmp = []; //以id為健,$value為值的容器,可以很巧妙的判斷根節(jié)點(diǎn)元素 $tree = []; //利用引用,對$data的數(shù)據(jù)進(jìn)行操作 foreach ($data as $key => &$value) { // $tmp[$value["id"]] = &$value; if (!isset($tmp[$value["pid"]])) { $tree[] = &$tmp[$value["id"]]; }else { $temp = &$tmp[$value["pid"]]; $temp[$child][] = &$value; } unset($temp, $value); } return $tree; }
ok,先不說其他的,你先拿下面的數(shù)據(jù)測試下這個方法.
$data= [ ["id" => 1, "pid" => 0 , "name" => "Universe"], ["id" => 2, "pid" => 1 , "name" => "Earth"], ["id" => 3, "pid" => 2 , "name" => "China"], ["id" => 4, "pid" => 3 , "name" => "Beijing"], ];
補(bǔ)充:這個方法需要注意一點(diǎn),需要父節(jié)點(diǎn)在前,不適合無序數(shù)據(jù),所以如果是無序的,先得排序.
如果沒有意外,打印的結(jié)果,應(yīng)該如下:
array(1) { [0]=> array(4) { ["id"]=> int(1) ["pid"]=> int(0) ["name"]=> string(8) "Universe" ["children"]=> array(1) { [0]=> array(4) { ["id"]=> int(2) ["pid"]=> int(1) ["name"]=> string(5) "Earth" ["children"]=> array(1) { [0]=> array(4) { ["id"]=> int(3) ["pid"]=> int(2) ["name"]=> string(5) "China" ["children"]=> array(1) { [0]=> array(3) { ["id"]=> int(4) ["pid"]=> int(3) ["name"]=> string(7) "Beijing" } } } } } } } }
如果到此,你還想不明白,沒關(guān)系,我們一一來分析下.
其實(shí)要徹底弄明白這個解決方案,需要理解二個部分。
foreach賦值原理
引用的原理
foreach
$data = ["student", "teacher"]; foreach ($data as $index => $item) { }
注意每次循環(huán)的時候, 是把$data[0]和$data[1] 的“值”復(fù)制一份 再賦給 $item
引用(一定要自己動手試驗(yàn)下)
$a = 1; $b = &$a; $c = $b; $c = 2; 猜猜看 $b = ?;
如果引用有疑問,點(diǎn)我
到此,如果你能理解上面foreach和引用,并且能理解這個解決方案的所有執(zhí)行過程,那么恭喜你,你學(xué)的真好! 但如果還是有困難,沒關(guān)系,咱們一步一步踏踏實(shí)實(shí)的來.
Analysisok,深吸一口氣,跟著我的思路,咱們一步一步來.
首先咱們看下原函數(shù)
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { $tmp = []; #以id為健,$value為值的容器,可以很巧妙的判斷根節(jié)點(diǎn)元素 $tree = []; #利用引用,對$data的數(shù)據(jù)進(jìn)行操作 foreach ($data as $key => &$value) { #&$value取到$data元素對應(yīng)值的引用 $tmp[$value["id"]] = &$value; #以$value["id"]為鍵,&$value引用為值push到$tmp中, #這樣可以巧妙的判斷當(dāng)前元素是否為根節(jié)點(diǎn) if (!isset($tmp[$value["pid"]])) { #將根節(jié)點(diǎn)push到$tree中 $tree[] = &$tmp[$value["id"]]; }else { #若當(dāng)前元素的父節(jié)點(diǎn)存在于$tmp中, 引用獲取$tmp中對應(yīng)父節(jié)點(diǎn)的值 $temp = &$tmp[$value["pid"]]; #然后將當(dāng)前元素push到其父節(jié)點(diǎn)的children中 $temp[$child][] = &$value; } #為了不引起變量污染, 引用用完后,需要unset掉 unset($temp, $value); } return $tree; }
第一次循環(huán)
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { # $tmp = []; # $tree = []; # foreach ($data as $key => &$value) { // $tmp[$value["id"]] = &$value; if (!isset($tmp[$value["pid"]])) { $tree[] = &$tmp[$value["id"]]; }else { # $temp = &$tmp[$value["pid"]]; # $temp[$child][] = &$value; # } unset($temp, $value); } return $tree; }
變量情況:
$data[0] = ["id" => 1, "pid" => 0 , "name" => "Universe"];
$tmp[1] = &$data[0];
$tree[] = &$data[0]
第二次循環(huán)
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { # $tmp = []; # $tree = []; # foreach ($data as $key => &$value) { // $tmp[$value["id"]] = &$value; # if (!isset($tmp[$value["pid"]])) { # $tree[] = &$tmp[$value["id"]]; }else { $temp = &$tmp[$value["pid"]]; $temp[$child][] = &$value; } unset($temp, $value); } return $tree; }
變量情況:
$data[1] = ["id" => 2, "pid" => 1 , "name" => "Earth"];
$value=&$data[1];
$tmp[2] = &$data[1];
注意:
$temp即&$tmp[1],即和$data[0]指向相同的地址
所以$temp["children"][] = &$value ,操作的結(jié)果是:
$data[ [ "id" => 1, "pid" => 0 , "name" => "Universe" "children"=>[ &$data[1], //注意:存儲的是引用 ] ] ... ]
4.第三次循環(huán)
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { # $tmp = []; # $tree = []; # foreach ($data as $key => &$value) { // $tmp[$value["id"]] = &$value; # if (!isset($tmp[$value["pid"]])) { # $tree[] = &$tmp[$value["id"]]; }else { $temp = &$tmp[$value["pid"]]; $temp[$child][] = &$value; } unset($temp, $value); } return $tree; }
變量情況:
$data[2] = ["id" => 3, "pid" => 2 , "name" => "China"];
$value = &$data[2];
$tmp[3] = &$data[2];
注意:
$temp即&$tmp[2],即和$data[1]指向相同的地址
所以$temp["children"][] = &$value ,操作的結(jié)果是:
這里注意一下:
這是第二次循環(huán)的時候,children中存儲的$data[1]的引用
$data[ [ "id" => 1, "pid" => 0 , "name" => "Universe" "children"=>[ &$data[1], //注意:存儲的是引用 ] ] ... ]
第三次循環(huán)的的時候,則是$data[1]["children"][] = &$value, 而$value指向的是$data[2]
,所以結(jié)果是:
$data[ [ "id" => 1, "pid" => 0 , "name" => "Universe" "children"=>[ // &$data[1], //注意:存儲的是引用 [ "id" => 2, "pid" => 1 , "name" => "Earth" "children" => [ &data[2] //注意:存儲的是引用 ] ] ] ] ] ... ]
5.第四次循環(huán)
function buildTreeByReference($data, $id = "id", $pid = "pid", $child = "children") { # $tmp = []; # $tree = []; # foreach ($data as $key => &$value) { // $tmp[$value["id"]] = &$value; # if (!isset($tmp[$value["pid"]])) { # $tree[] = &$tmp[$value["id"]]; }else { $temp = &$tmp[$value["pid"]]; $temp[$child][] = &$value; } unset($temp, $value); } return $tree; }
變量情況:
$data[3] = ["id" => 4, "pid" => 3 , "name" => "Beijing"];
$value = &$data[3];
$tmp[3] = &$data[3];
注意:
$temp即&$tmp[2],即和$data[1]指向相同的地址
所以$temp["children"][] = &$value ,操作的結(jié)果是:
這里注意一下:
這是第三次循環(huán)的時候,children中存儲的$data[2]的引用
$data[ [ "id" => 1, "pid" => 0 , "name" => "Universe" "children"=>[ // &$data[1], //注意:存儲的是引用 [ "id" => 2, "pid" => 1 , "name" => "Earth" "children" => [ &data[2] //注意:存儲的是引用 ] ] ] ] ] ... ]
第四次循環(huán)的的時候,則是$data[2]["children"][] = &$value, 而$value指向的是$data[3]
,所以結(jié)果是:
$data[ [ "id" => 1, "pid" => 0 , "name" => "Universe" "children"=>[ // &$data[1], //注意:存儲的是引用 [ "id" => 2, "pid" => 1 , "name" => "Earth" "children" => [ // &data[2] //注意:存儲的是引用 [ "id" => 3, "pid" => 2 , "name" => "China" "children" =>[ &$data[3]; //注意:存儲的是引用 ] ] ] ] ] ] ] ... ]
ok,至此,整個執(zhí)行過程走通了,你懂了嗎?:)
對了,還另外一個方法,也是通過引用的,這個我就不分析,要是理解上面的方法,下面的相對來說簡單些。
public static function buildTreeByReference1($data, $id = "id", $pid = "pid", $child = "children") { $tmp = []; foreach ($data as $key => $value) { $tmp[$value[$id]] = $value; } $tree = []; foreach ($tmp as $key => $value) { if (isset($tmp[$value["pid"]])) { $tmp[$value["pid"]]["children"][] = &$tmp[$key]; }else{ $tree[] = &$tmp[$key]; } } return $tree; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/28600.html
摘要:即產(chǎn)生了相當(dāng)于這樣的效果,所以改變的值也同時改變了的值。不要用返回引用來增加性能,引擎足夠聰明來自己進(jìn)行優(yōu)化。只能從函數(shù)返回引用變量沒別的方法。 關(guān)鍵是對global的誤解,之前以為在函數(shù)中g(shù)lobal變量,就是把函數(shù)外部的變量拿進(jìn)函數(shù)內(nèi)部使用,但似乎我錯了引用傳遞+unset+global理解 php的引用(就是在變量、函數(shù)、對象等前面加上&符號)在PHP中引用的意思是:不同的名字訪...
摘要:發(fā)布時最大的變動是對象處理方式。這很容易被誤解為引用,但是存儲器的引用與引用是完全不同的概念。使用引用是一件不好的事情,除了引用本身不好,并且還會使性能下降這個事實(shí)外,使用引用這種方式會使得代碼難以維護(hù)。 showImg(https://segmentfault.com/img/remote/1460000014082570); 去年我參加了很多次會議,其中八次會議里我進(jìn)行了相關(guān)發(fā)言,...
摘要:已經(jīng)發(fā)布如承諾我也要開始這個系列的文章的編寫今天我想先和大家聊聊的變化在講變化的之前我們先來看看在下面是什么樣子回顧在的時候的定義如下對內(nèi)核有了解的同學(xué)應(yīng)該對這個結(jié)構(gòu)比較熟悉因?yàn)榭梢员硎疽磺兄械臄?shù)據(jù)類型所以它包含了一個字段表示這個存儲的是什 PHP7已經(jīng)發(fā)布, 如承諾, 我也要開始這個系列的文章的編寫, 今天我想先和大家聊聊zval的變化. 在講zval變化的之前我們先來看看zval在...
摘要:文章來自原文在給開發(fā)者的源碼系列的第三篇文章,我們打算擴(kuò)展上一篇文章來幫助理解內(nèi)部是怎么工作的。進(jìn)入在的核心代碼中,變量被稱為。要轉(zhuǎn)換一個為值,就調(diào)用函數(shù)。有了這個東西,我們可以看到函數(shù)馬上調(diào)用函數(shù)。 文章來自:http://www.hoohack.me/2016/02/12/phps-source-code-for-php-developers-part3-variables-ch...
摘要:單例模式顧名思義,就是只有一個實(shí)例。為什么要使用單例模式語言本身的局限性語言是一種解釋型的腳本語言,這種運(yùn)行機(jī)制使得每個頁面被解釋執(zhí)行后,所有的相關(guān)資源都會被回收。 單例模式(Singleton Pattern):顧名思義,就是只有一個實(shí)例。作為對象的創(chuàng)建模式,單例模式確保某一個類只有一個實(shí)例,而且自行實(shí)例化并向整個系統(tǒng)提供這個實(shí)例。 為什么要使用單例模式 1、PHP語言本身的局限性P...
閱讀 1237·2023-04-25 15:53
閱讀 2108·2021-11-19 09:40
閱讀 3495·2021-10-11 10:59
閱讀 2075·2019-08-30 15:55
閱讀 1963·2019-08-30 15:54
閱讀 2308·2019-08-29 13:03
閱讀 2761·2019-08-28 18:17
閱讀 1516·2019-08-27 10:51