说明

这里基于 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. hive实践_01

    本地一份包含有中文的文本文件在上传到hive前,需要先转化为UTF-8格式,否则会出现乱码.(notepad++ 格式>>>转化UTF-8编码格式)   -------------- ...

  2. [C++]请麻烦压一下定理的棺材板啦

    从去年还在竞赛的时候2/12的原博客里搬运来的 不得不说之前取名真的很艺术qwq 今天开始上的数论课,让头发以肉眼可见的速度掉落emmm 没关系我头发多我不怕啦啦啦QwQ 其中最令人头疼的就是那些人名 ...

  3. Natas3 Writeup(爬虫协议robots.txt)

    Natas3: 页面提示本页面什么都没有. 在源码中发现提示:无信息泄露,谷歌这次不会发现它.提到了搜索引擎,猜测爬虫协议robots.txt中存在信息泄露,访问网站爬虫协议http://natas3 ...

  4. python关于字典如何格式化地写入文件之中

    1.python关于字典如何式化地写入文件之中 如何写入:https://blog.csdn.net/qq_15642411/article/details/79943741 (推荐使用json包) ...

  5. iOS开发:十六进制颜色转UIColor

    Objective-C UIColor * __nullable UIColorFromHexValue(NSUInteger hexValue) { CGFloat red = (hexValue ...

  6. Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan (解读人:王茹凯)

    文献名:Bisecting GlcNAc is a general suppressor of terminal modification of N-glycan(平分GlcNAc是N-聚糖末端修饰的 ...

  7. jenkins-gitlab-harbor-ceph基于Kubernetes的CI/CD运用(二)

    一张网图 因为我们使用了Docker in Docker技术,就是把jenkins部署在k8s里.jenkins master会动态创建slave pod,使用slave pod运行代码克隆,项目构建 ...

  8. Centos 非root用户安装rabbitmq

    RabbitMQ是一个开源消息队列服务器,您可以使用它来构建您的消息传递应用程序.简单地说,您可以将来自一个应用程序的消息放入队列,并从来自相同应用程序或不同应用程序的队列中检索消息.您可以使用多种编 ...

  9. 自定义实现 PyQt5 下拉复选框 ComboCheckBox

    一.前言 由于最近的项目需要具有复选功能,但过多的复选框会影响界面布局和美观,因而想到把 PyQt5 的下拉列表和复选框结合起来,但在 PyQt5 中并没有这样的组件供我们使用,所以想要自己实现一个下 ...

  10. [Linux系统] CentOS7(RHEL7)重置root用户密码

    1.系统启动时,按"e"进入编辑界面 2.编辑内容 将rhgb quiet修改为 init=/bin/sh : 然后按 ctrl+x . 3.修改root密码 mount -o r ...