说明

这里基于 php7.2.5 进行测试,php7 之后内部结构变化应该不是太大,但与 php5.X 有差别。

什么是引用

在 PHP 中引用是一种数据类型 (结构),是指 指向同一个类型的数据结构,来看具体存储结构

struct _zend_reference {
// 引用计数用于垃圾回收 先忽略
zend_refcounted_h gc;
// zval是另一个变量 zval还记得吗 存储变量的结构
// 这里val指向另一个zval
zval val;
};

  

忘了的这里看 zval

如何使用

// 定义变量
$a = "hello";
// &生成引用变量
$b = &$a; echo $b; echo PHP_EOL; php hello.php hello

  

结果大家都知道,$b 与 $a 的值是相同的,而且你还知道,修改 $b 同时也会作用与 $a.

$a = "hello";
$b = &$a; echo "b:".$b; echo PHP_EOL; $b = "world"; echo "a:".$a; echo PHP_EOL; php hello.php b:hello
a:world

  

如何实现

回忆 zval 的格式执行第一句时,生成的数据结构是这样的 (简版示意图,真实结构复杂)

当执行 $b = &$a 时,&$a 会先生成引用类型的数据结构,然后引用的 zval 指向之前的 hello 的结构,$a,$b 则共同指向引用结构。

那么在修改 $b 时,实际是修改了引用类型指向的 zend_value,所以导致 $a 的值也发生了变化。

小结

php 中使用 & 生成一个引用类型的数据,这个引用的 zval 指向原变量所指向的 zval, 变量则会指向这个应用结构,当发生引用赋值之后,被赋值的变量也会指向这个引用,更改其中任何一个变量,所有的变量都会发生变化。类似于你大名叫大壮,小名叫小壮,但是身份证都是 xxoo100, 无论修改大壮还是小壮的身份证,他始终只有一个身份证。

扩展

我们可能听过取地址符这么一种说法,那么在 C 语言或者 GO 中,通过使用 & 可以获取到变量的内存地址。

#include <stdio.h>
#include<string.h> int main()
{
char str[] = "hello";
// &获取变量的内存地址
printf("%p\n", &str);
} gcc pointer.c -o pointer
./pointer 0x7ffee6d3292a

  

但是 PHP 的 & 并不是获取变量的地址,这是需要注意的。

unset 引用变量

unset($b);
echo "a:".$a; echo PHP_EOL;
echo "b:".$b; echo PHP_EOL; php hello.php a:world
PHP Notice: Undefined variable: b

  

unset ($b) 之后,只是销毁了变量 b 及 b 对引用的指向,没有影响 $a。

foreach 中的引用

$list = [
['id' => 3, 'total' => 3],
['id' => 4, 'total' => 4],
['id' => 5, 'total' => 5],
]; foreach ($list as $key => &$info) {
$info['total'] = $info['total'] + 3;
} print_r($list); // 一顿操作
$info['name'] = "hello";
print_r($info); php hello.php Array
(
[0] => Array
(
[id] => 3
[total] => 6
) [1] => Array
(
[id] => 4
[total] => 7
) [2] => Array
(
[id] => 5
[total] => 8
) ) Array
(
[id] => 5
[total] => 8
[name] => hello
)

  

这里在 foreach 之后需要把 info unset 掉防止发生数据问题。

总结

PHP 中通过 & 获取对变量的引用,实质是多个变量通过中间引用类型(不是指向内存地址),指向同一个值。

PHP高级开发工程师简历打造,祝你金三银四跳槽加薪

PHP 语法引用使用及实现的更多相关文章

  1. 前端 -- javas-基本语法/引用等

    javas-基本语法/引用等 JavaScript介绍 JavaScript是运行在浏览器端的脚步语言,JavaScript主要解决的是前端与用户交互的问题,包括使用交互与数据交互. JavaScri ...

  2. CSS-基本语法/引用/文本设置/选择器/css3属性

    CSS-基本语法/引用/文本设置 css基本语法及页面引用 css基本语法 css的定义方法是: 选择器 { 属性:值; 属性:值; 属性:值;} 选择器是将样式和页面元素关联起来的名称,属性是希望设 ...

  3. C++中对C的扩展学习新增语法——引用

    引用 引用的好处: 1.引用的好处 C++使用结构体,不需要再使用 typedef. 2.值传递是将实参进行拷贝,赋值给形参,如果对象比较大,每次拷贝效率比较低,并且函数内部无法修改外部变量的值,能力 ...

  4. Mybatis通过GNDL语法引用静态常量或者枚举类型

    原因:mybatis 中mapper.xml 文件中需要静态常量的时候 使用: 先定义: public static String aa="aa"; ${@全路径类名称@静态变量| ...

  5. Typora - Markdown 语法说明

    Typora 是 Windows 下最好的 Markdown 编辑器!不接受反驳~ 导图 快捷键标题:Ctrl + 数字 Ctrl + 123456 代表 H1-H6 级标题Ctrl + 0 恢复普通 ...

  6. markdown语法测试集合

    这篇文章包含markdown语法基本的内容, 目的是放在自己的博客园上, 通过开发者控制台快速选中, 从而自定义自己博客园markdown样式.当然本文也可以当markdown语法学习之用. 在mar ...

  7. AT&T汇编和Intel汇编语法主要区别

    AT&T使用$表示立即操作数,而Intel的立即操作数是不需要界定的.因此,使用AT&T语法引用十进制值4时,使用$4,使用Intel语法时只需使用4.   AT&T在寄存器名 ...

  8. 教你如何在 Javascript 文件里使用 .Net MVC Razor 语法

    摘录 文章主要是介绍了通过一个第三方类库RazorJS,实现Javascript 文件里使用 .Net MVC Razor 语法,很巧妙,推荐给大家 相信大家都试过在一个 View 里嵌套使用 jav ...

  9. es6引用模块import后面加上花括号{}和不加花括号的区别

    在使用import语法引用模块时,如何正确使用{} 例如:有两个文件,home.js.user.js 当需要在home.js中引入user.js的时候 //home.js import user fr ...

随机推荐

  1. bash编程练习,带选项,添加或删除用户

    脚本练习题: 可以接受选项及参数,而后能获取每一个选项,及选项的参数,并能根据选项及参数做出特定的操作: 比如:adminusers.sh -a|--add user .. -d|--del user ...

  2. Data-independent acquisition mass spectrometry in metaproteomics of gut microbiota - implementation and computational analysis DIA技术在肠道宏蛋白质组研究中的方法实现和数据分析 (解读人:闫克强)

    文献名:Data-independent acquisition mass spectrometry in metaproteomics of gut microbiota - implementat ...

  3. ABP实践(4)-abp前端vue框架之简单商品增删改查(帮助刚入门的新手快速了解怎么才能加入自己的功能并运行起来)

    提示:如有不明白的地方请先查看前3篇ABP实践系列的文章 1,下载及启动abp项目前后端分离(netcore+vue) 2,修改abp数据库为mysql 3,商品系列api接口(本文主要依赖在这个商品 ...

  4. LocalStorage与SessionStorage

    localStorage与sessionStorage 每日更新前端基础,如果觉得不错,点个star吧

  5. cmdb 配置

    cmdb客户端文件夹创建 客户端:client:-bin:启动文件-src:源文件(核心代码)-conf:配置文件-lib:全局的一些方法 和配置-test:测试文件

  6. cmdb简介

    目录: 1.为啥要做cmdb

  7. hdu1171kmp果题

    题目链接:http://icpc.njust.edu.cn/Problem/Hdu/1711/ #include<bits/stdc++.h> using namespace std; t ...

  8. sql学习~pivot和unpivot用法

    pivot  可以把列值转换为输出中的多个列. pivot 可以在其他剩余的列的值上执行聚合函数. unpivot 将列转换为列值 语法 SELECT <non-pivoted column&g ...

  9. 【翻译】如何使用 OpenVINO 来优化 OpenCV

    本文翻译自 Vishwesh Shrimali 的  "Using OpenVINO with OpenCV" 原文链接: https://www.learnopencv.com/ ...

  10. OpenCV-Python 理解特征 | 三十六

    目标 在本章中,我们将尝试理解什么是特征,为什么拐角重要等等 解释 你们大多数人都会玩拼图游戏.你会得到很多小图像,需要正确组装它们以形成大的真实图像.问题是,你怎么做?将相同的理论投影到计算机程序上 ...