资讯专栏INFORMATION COLUMN

PHP的引用,你知道多少?

williamwen1986 / 931人阅读

摘要:最近面试他人的过程中,问了一些关于引用的知识,发现很多同学对这方面知之甚少,还有很多工作中基本没有使用过。没钱给大家发红包,给大家推荐一家上海的好公司。对于上海的小伙伴或者想去上海的小伙伴,强烈建议去看看。

真的是变懒了,一个月一篇的节凑都很难保证了。

最近面试他人的过程中,问了一些关于PHP引用的知识,发现很多同学对这方面知之甚少,还有很多工作中基本没有使用过。甚至有人告诉我要少用引用,引用会带来一些诡异的问题。我心里默默说,避免诡异的问题是要去理解引用而不是少用引用。今天一起来解析解析。

场景假设

先从一个引用的所谓诡异问题开始。假设我们有这个场景:我们从数据库中读取了一组订单数据,需要把订单的每条数据多带带做些处理。

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

foreach ($list as &$item) {
    // 对订单做了些什么处理
}

// 有了一些其它操作

$result = [];// 需要返回的结果
foreach ($list 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。很多同学说预防这种问题,就要少用引用。这种态度太消极了,引用在很多地方带来了代码书写的简洁,并且针对大数组使用引用能够节省大量的内存。

诡异问题解析

现在我们来分析下上面问题出现的原因。先来看引用的定义

引用意味着用不同的名字访问同一个变量内容。

那么在这部分代码中

foreach ($list as &$item) {
    // 对订单做了些什么处理
}

$item 最后跟 $list[2] 指向了同一个变量内容。并且在 foreach 循环完后,$item 并没有被销毁,因此在后续如果同名的话,会继续生效。图示如下:

那么再接下来的的另一个循环中。

foreach ($list as $item) {// 重新映射名字
    $result[] = [
        "order_id" => $item["orderid"],
        "amount" => $item["total_fee"],
    ];
}

每当 $list 把变量赋值给 $item 的时候,都同时改变了 $list[2] 的值。因此才会出现上面诡异的情况。我来逐步给大家演示下:

第一次循环 $list[0]$item 指向 orderid=123 的订单,由于 $item$list[2] 的引用,此时导致 $orders[2] 也指向了 orderid=123 的订单;

第二次循环 $list[1], $item 指向 orderid=456 的订单,因此 $list[2] 也指向了 orderid=456

第三次循环 $list[2]的时候,明显其值已经变成了 orderid=456 的订单。

通过上面的分析,我相信大家对引用所谓的诡异有了了解。那么又该如何避免这种情况出现呢?其实很简单,每次使用完引用后,记得 unset 调引用。在后面便可毫无顾忌的继续使用了。具体到本例子就是:

foreach ($list as &$item) {
    // 对订单做了些什么处理
}
unset($item);

// 有了一些其它操作

foreach ($list 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"]];
    }
}

大家可以试试不用引用的方式,把无限级实现出来试试,比较下代码。


年底了。没钱给大家发红包,给大家推荐一家上海的好公司。为大家跳槽助力。

公司网站: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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26230.html

相关文章

  • 深入理解PHP7之zval

    摘要:已经发布如承诺我也要开始这个系列的文章的编写今天我想先和大家聊聊的变化在讲变化的之前我们先来看看在下面是什么样子回顾在的时候的定义如下对内核有了解的同学应该对这个结构比较熟悉因为可以表示一切中的数据类型所以它包含了一个字段表示这个存储的是什 PHP7已经发布, 如承诺, 我也要开始这个系列的文章的编写, 今天我想先和大家聊聊zval的变化. 在讲zval变化的之前我们先来看看zval在...

    Yuanf 评论0 收藏0
  • php7内核阅读(1)--数据容器zval和zend_value

    摘要:本文主要是针对,的话可以移步到庆哥的博客看,还有就是小菜我读的是内核剖析这本书。接下来我会使用到来调试源码本文有参照博客中的部分内容以及代码。 前言 工作+实习快一年了,搞php后端开发,一直很迷茫怎么提高自己,就先从php源码开始吧,本人比较菜,本文章写的比较赶时间,所以有什么错误或者漏掉的地方,望各位大神指正,多交流才能成长嘛,嘿嘿。本文主要是针对php7,php5的话可以移步到庆...

    canger 评论0 收藏0
  • 译文-垃圾回收器是什么

    摘要:垃圾回收器追踪所有正在使用的对象,将无用对象标记为垃圾。自动化指针内存回收自动化的最好方式之一是使用钩子函数。它们可能因为多种原因发生,但是这种垃圾回收器是最主流的一种。 原文出处:What Is Garbage Collection? 一眼就应该从名称看出垃圾回收机制的含义-查找垃圾,然后丢弃。事实正好相反。垃圾回收器追踪所有正在使用的对象,将无用对象标记为垃圾。请留意,我们开始研究...

    alanoddsoff 评论0 收藏0
  • 入门 JavaScript ES6 (五) 集合

    摘要:一概述集合是引入的新的内置对象类型,其特点同数学意义的集合,即集合内所有元素不重复元素唯一。数组集合对比数组和集合,数组可以加入重复数据,而集合的所有元素是唯一的不允许重复。因此,适合临时存放一组对象,以及存放跟对象绑定的信息。 本文同步带你入门 带你入门 JavaScript ES6 (五) 集合,转载请注明出处。 前面我们学习了: for of 变量和扩展语法 块作用域变量和解构...

    BetaRabbit 评论0 收藏0
  • 10个值得深思PHP面试问题

    摘要:运算符的优先级,是明显高于,因此先执行再执行。这里会非常有趣的将转换成一个数字而且默认去掉了前面的也就是很显然上面的问题已经说过了数字和字符串类型不一致。 showImg(https://segmentfault.com/img/bVvhhO); 本文翻译自:https://www.toptal.com/php/interview-questions ,文章所罗列的问题虽然看似简单,但...

    BetaRabbit 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<