当前位置: 首页 > 后端技术 > PHP

重新理解-PHP引用

时间:2023-03-30 00:26:09 PHP

原因:在日常开发中,我们会遇到需要构造树,通过id和pid的关系构建树结构,然后进行遍历树等操作。它的实现分为两种方式:1.递归,2.引用,这两种方式的优缺点也很明显。递归比较容易实现,但是随着数据量的增加,它的性能很低。citation这个概念本身很容易理解,性能也很好,但是要用好还是有一定门槛的,写起来也不容易。之所以写这篇文章,是因为这几天遇到了一个很好的解决方案,让我重新理解了参考。通过本文,总结自己的学习成果。好了,那就直接上代码吧。实践一下,如果看完下面的代码你能看懂,就说明你已经学会引用了,可以直接跳过本文。函数buildTreeByReference($data,$id='id',$pid='pid',$child="children"){$tmp=[];//以id为key,$value为value的容器,可以很巧妙的判断根节点元素$tree=[];//使用引用对$data的数据进行操作foreach($dataas$key=>&$value){//$tmp[$value['id']]=&$value;如果(!isset($tmp[$value['pid']])){$tree[]=&$tmp[$value['id']];}else{$temp=&$tmp[$value['pid']];$temp[$child][]=&$value;}未设置($temp,$value);}返回$树;首先用下面的数据测试这个方法。$data=[["id"=>1,"pid"=>0,"name"=>'Universe'],["id"=>2,"pid"=>1,"name"=>'地球'],["id"=>3,"pid"=>2,"name"=>'中国'],["id"=>4,"pid"=>3,"name"=>'北京'],];补充:这个方法需要注意,父节点需要在前面,不适合无序的数据,所以如果是无序的,必须先排序。如无意外,打印出来的结果应该是这样的: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)"北京"}}}}}}}如果你还是不懂没关系,下面我们一一分析。事实上,要完全理解这个解决方案,你需要理解两部分foreach赋值原理引用的原理foreach$data=["student","teacher"];foreach($dataas$index=>$item){}注意每次循环的时候,$data[0]和$copydata[1]的“值”赋值给$item引用(一定要试试你自己)$a=1;$b=&$a;$c=$b;$c=2;猜见$b=?;如果您对参考文献有任何疑问,请单击此处。如果你能看懂上面的foreach和reference,并且理解这个方案的所有执行过程,那么恭喜你,学得很好!但是如果你还有Difficult,没关系,我们一步步来吧。Analysisok,深吸一口气,跟着我的思路,一步步来吧。首先我们看一下原函数functionbuildTreeByReference($data,$id='id',$pid='pid',$child="children"){$tmp=[];#以id为key,$value为value的容器,可以巧妙判断根节点元素$tree=[];#使用引用,对$data的数据进行操作foreach($dataas$key=>&$value){#&$value获取$data元素对应的value的引用$tmp[$value['id']]=&$价值;#以$value['id']为键,&$value引用为值推送到$tmp,#这样可以巧妙判断当前元素是否为根节点if(!isset($tmp[$value['pid']])){#将根节点推入$tree$tree[]=&$tmp[$值['id']];}else{#如果$tmp中存在当前元素的父节点,则通过引用获取$tmp中对应父节点的值$temp=&$tmp[$value['pid']];#然后将当前元素推送到其父节点的子节点$temp[$child][]=&$value;}#为了不造成变量污染,引用用完后,需要unsetunset($temp,$value);}返回$树;}第一个循环函数buildTreeByReference($data,$id='id',$pid='pid',$child="children"){#$tmp=[];#$树=[];#foreach($dataas$key=>&$value){//$tmp[$value['id']]=&$value;如果(!isset($tmp[$value['pid']])){$tree[]=&$tmp[$value['id']];}else{#$temp=&$tmp[$value['pid']];#$temp[$child][]=&$value;#}未设置($临时,$价值);}返回$树;}变量:$data[0]=["id"=>1,"pid"=>0,"name"=>'Universe'];$tmp[1]=&$data[0];$tree[]=&$data[0]第二个循环函数buildTreeByReference($data,$id='id',$pid='pid',$child="儿童"){#$tmp=[];#$树=[];#foreach($dataas$key=>&$value){//$tmp[$value['id']]=&$value;#if(!isset($tmp[$value['pid']])){#$tree[]=&$tmp[$value['id']];}else{$temp=&$tmp[$value['pid']];$temp[$child][]=&$value;}未设置($temp,$value);}返回$树;}变量情况:$data[1]=["id"=>2,"pid"=>1,"name"=>'Earth'];$value=&$data[1];$tmp[2]=&$数据[1];注:$temp为&$tmp[1],与$data[0]指向同一个地址所以$temp['children'][]=&$value,运算结果为:$data[["id"=>1,"pid"=>0,"name"=>'Universe'"children"=>[&$data[1],//注意:存储引用]]...]4。第三个循环函数buildTreeByReference($data,$id='id',$pid='pid',$child="children"){#$tmp=[];#$树=[];#foreach($dataas$key=>&$value){//$tmp[$value['id']]=&$value;#if(!isset($tmp[$value['pid']])){#$tree[]=&$tmp[$value['id']];}else{$temp=&$tmp[$value['pid']];$temp[$child][]=&$value;}未设置($temp,$value);}返回$树;}变量情况:$data[2]=["id"=>3,"pid"=>2,"name"=>'China'];$value=&$data[2];$tmp[3]=&$数据[2];注意:$temp是&$tmp[2],与$data[1]相同,所以$temp['children'][]=&$value,运算结果为:这里注意:这是在第二次循环$data[["id"=>1,"pid"=>0,"name"=>'Universe'"children"=>[&$data[1],//注意:存储是引用]]...]执行到第三个循环时,就是$data[1]]['children'][]=&$value,$value指向$data[2],所以结果为:$data[["id"=>1,"pid"=>0,"name"=>'Universe'"children"=>[//&$data[1],//注意:存储的是引用["id"=>2,"pid"=>1,"name"=>'Earth'"children"=>[&data[2]//注意:引用被存储]]]]]...]5.第四个循环函数buildTreeByReference($data,$id='id',$pid='pid',$child="children"){#$tmp=[];#$树=[];#foreach($dataas$key=>&$value){//$tmp[$value['id']]=&$value;#if(!isset($tmp[$value['pid']])){#$tree[]=&$tmp[$value['id']];}else{$temp=&$tmp[$value['pid']];$temp[$child][]=&$value;}未设置($temp,$value);}返回$树;}变量:$data[3]=["id"=>4,"pid"=>3,"name"=>'北京'];$value=&$data[3];$tmp[3]=&$data[3];注意:$temp是&$tmp[2],和$data[1]指向同一个地址所以$temp['children'][]=&$value,运行结果为:这里注意:this是引用$data[["id"=>1,"pid"=>0,"name"=>'Universe'"children"=>[//&$data[1],//注意:存储的是引用["id"=>2,"pid"=>1,"name"=>'Earth'"children"=>[&data[2]//注意:存的是引用]]]]]...]第四次循环时,就是$data[2]['children'][]=&$value,$value指向$data[3],所以结果是:$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];//注意:storage是引号]]]]]]]...]ok,至此,整个执行过程就走完了,明白了吗?:)对了,还有一个方法,也是引用。这个我就不分析了。如果你理解了上面的方法,下面这个就比较简单了publicstaticfunctionbuildTreeByReference1($data,$id='id',$pid='pid',$child="children"){$tmp=[];foreach($dataas$key=>$value){$tmp[$value[$id]]=$value;}$树=[];foreach($tmpas$key=>$value){if(isset($tmp[$value['pid']])){$tmp[$value['pid']]['children'][]=&$tmp[$键];}else{$tree[]=&$tmp[$key];}}返回$树;}