• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

再理解PHP引用

php 搞代码 3年前 (2022-01-22) 22次浏览 已收录 0个评论
文章目录[隐藏]

这篇文章主要介绍了再理解PHP引用,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

起因:

日常开发中,我们会碰到构造树的需求,通过id,pid的关系去构建一个树结构,然后对树进行遍历等操作。其实现方式分为两种: 1. 递归, 2. 引用
而这两个方法的优缺点也很明显。

  1. 递归实现起来较容易,但是随着数着数据量的增大,其性能很低。

  2. 引用本身概念好理解,性能也很好,但是用好它还是存在着一定的门槛,不太好写。

写本文的起因是,这几天碰到非常好的一个解决方案,让我重新理解了引用。通过本文,总结下自己的学习成果.ok,那直接上代码了。

Practise

如果下面的代码,你看完就能理解了,说明你引用真是学到家了, 你也可以直接跳过本文哈~。

function buildTreeByReference($data, $id = 'id', $pid = 'pid', $child = "children")    {        $tmp = []; //以id为健,$value为值的容器,可以很巧妙的判断根节点元素        $tree = [];          //利用引用,对$data的数据进行操作        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,先不说其他的,你先拿下面的数据测试下这个方法.

$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'],];

补充:这个方法需要注意一点,需要父节点在前,不适合无序数据,所以如果是无序的,先得排序.

如果没有意外,打印的结果,应该如下:

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"              }            }          }        }      }    }  }}

如果到此,你还想不明白,没关系,我们一一来分析下.
其实要彻底弄明白这个解决方案,需要理解二个部分。

  1. foreach赋值原理

  2. 引用的原理

foreach

    $data = ["student", "teacher"];    foreach ($data as $index => $item) {    }

注意每次循环的时候, 是把$data[0]和$data[1] 的“值”复制一份 再赋给 $item

引用(一定要自己动手试验下)

$a = 1;$b = &$a;$c = $b;$c = 2;猜猜看 $b = ?;

如果引用有疑问,点我

到此,如果你能理解上面foreach和引用,并且能理解这个解决方案的所有执行过程,那么恭喜你,你学的真好! 但如果还是有困难,没关系,咱们一步一步踏踏实实的来.

Analysis

ok,深吸一口气,跟着我的思路,咱们一步一步来.

  1. 首先咱们看下原函数

function buildTreeByReference($data, $id = 'id', $pid = 'pid', $child = "children")    {        $tmp = []; #以id为健,$value为值的容器,可以很巧妙的判断根节点元素        $tree = [];          #利用引用,对$data的数据进行操作        foreach ($data as $key => &$value) {                                #&$value取到$data元素对应值的引用                                $tmp[$value['id']] = &$value;                                #以$value['id']为键,&$value引用为值push到$tmp中,                #这样可以巧妙的判断当前元素是否为根节点                                if (!isset($tmp[$value['pid']])) {                    #将根节点push到$tree中                    $tree[] = &$tmp[$value['id']];                                    }else {                     #若当前元素的父节点存在于$tmp中, 引用获取$tmp中对应父节点的值                     $temp = &$tmp[$value['pid']];                     #然后将当前元素push到其父节点的children中                     $temp[$child][] = &$value;                }                #为了不引起变量污染, 引用用完后,需要unset掉                unset($temp, $value);        }        return $tree;    }
  1. 第一次循环

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]

  1. 第二次循环

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 ,操作的结果是:

$data[    [       "id" => 1,     "pid" => 0 ,     "name" => 'Universe'     "children"=>[                 &$data[1],   //注意:存储的是引用         ]     ]        ...]

4.第三次循环

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 ,操作的结果是:
这里注意一下:
这是第二次循环的时候,children中存储的$data[1]的引用

$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.第四次循环

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 ,操作的结果是:
这里注意一下:
这是第三次循环的时候,children中存储的$data[2]的引用

   $data[        [           "id" => 1,         "pid" => 0 ,         "name" =&<div>)本文来源gaodai.ma#com搞#代!码网_</div><strong>搞代gaodaima码</strong>gt; '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];  //注意:存储的是引用                                                                  ]                                  ]                              ]                                                  ]                                               ]             ]         ]            ...    ]

ok,至此,整个执行过程走通了,你懂了吗?:)

对了,还另外一个方法,也是通过引用的,这个我就不分析,要是理解上面的方法,下面的相对来说简单些。

    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;    }

相关推荐:

php引用的几种用法实例汇总

以上就是再理解PHP引用的详细内容,更多请关注搞代码gaodaima其它相关文章!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:再理解PHP引用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址