PHP 语法引用使用及实现
说明
这里基于 php7.2.5 进行测试,php7 之后内部结构变化应该不是太大,但与 php5.X 有差别。
什么是引用
在 PHP 中引用是一种数据类型 (结构),是指 指向同一个类型的数据结构,来看具体存储结构
struct _zend_reference {
// 引用计数用于垃圾回收 先忽略
zend_refcounted_h gc;
// zval是另一个变量 zval还记得吗 存储变量的结构
// 这里val指向另一个zval
zval val;
};
如何使用
// 定义变量
$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 语法引用使用及实现的更多相关文章
- 前端 -- javas-基本语法/引用等
javas-基本语法/引用等 JavaScript介绍 JavaScript是运行在浏览器端的脚步语言,JavaScript主要解决的是前端与用户交互的问题,包括使用交互与数据交互. JavaScri ...
- CSS-基本语法/引用/文本设置/选择器/css3属性
CSS-基本语法/引用/文本设置 css基本语法及页面引用 css基本语法 css的定义方法是: 选择器 { 属性:值; 属性:值; 属性:值;} 选择器是将样式和页面元素关联起来的名称,属性是希望设 ...
- C++中对C的扩展学习新增语法——引用
引用 引用的好处: 1.引用的好处 C++使用结构体,不需要再使用 typedef. 2.值传递是将实参进行拷贝,赋值给形参,如果对象比较大,每次拷贝效率比较低,并且函数内部无法修改外部变量的值,能力 ...
- Mybatis通过GNDL语法引用静态常量或者枚举类型
原因:mybatis 中mapper.xml 文件中需要静态常量的时候 使用: 先定义: public static String aa="aa"; ${@全路径类名称@静态变量| ...
- Typora - Markdown 语法说明
Typora 是 Windows 下最好的 Markdown 编辑器!不接受反驳~ 导图 快捷键标题:Ctrl + 数字 Ctrl + 123456 代表 H1-H6 级标题Ctrl + 0 恢复普通 ...
- markdown语法测试集合
这篇文章包含markdown语法基本的内容, 目的是放在自己的博客园上, 通过开发者控制台快速选中, 从而自定义自己博客园markdown样式.当然本文也可以当markdown语法学习之用. 在mar ...
- AT&T汇编和Intel汇编语法主要区别
AT&T使用$表示立即操作数,而Intel的立即操作数是不需要界定的.因此,使用AT&T语法引用十进制值4时,使用$4,使用Intel语法时只需使用4. AT&T在寄存器名 ...
- 教你如何在 Javascript 文件里使用 .Net MVC Razor 语法
摘录 文章主要是介绍了通过一个第三方类库RazorJS,实现Javascript 文件里使用 .Net MVC Razor 语法,很巧妙,推荐给大家 相信大家都试过在一个 View 里嵌套使用 jav ...
- es6引用模块import后面加上花括号{}和不加花括号的区别
在使用import语法引用模块时,如何正确使用{} 例如:有两个文件,home.js.user.js 当需要在home.js中引入user.js的时候 //home.js import user fr ...
随机推荐
- JMeter报错:Address already in use : connect
Address already in use : connect的解决办法: 修改操作系统注册表1.打开注册表:regedit2.找到HKEY_LOCAL_MACHINE\SYSTEM\Current ...
- Journal of Proteome Research | iHPDM: In Silico Human Proteome Digestion Map with Proteolytic Peptide Analysis and Graphical Visualizations(iHPDM: 人类蛋白质组理论酶解图谱的水解肽段分析和可视化展示)| (解读人:邓亚美)
文献名:iHPDM: In Silico Human Proteome Digestion Map with Proteolytic Peptide Analysis and Graphical Vi ...
- 理解Golang组件protobuf
什么是protobuf protocol buffers 是一种语言无关.平台无关.可扩展的序列化结构数据的方法,它可用于(数据)通信协议.数据存储等.是一种灵活,高效,自动化机制的结构数据序列化方法 ...
- 说两个我在工作中有价值的bug
看了虫师在公众号上写的一边文章,叫做<面试官问,说一个你在工作非常有价值的bug>.看完虫师举的列子后,我也开始想之前测试的bug,想到之后,觉得有必要记录一下. First,在测试新闻动 ...
- 采用C++实现哈夫曼树的创建并输出哈夫曼编码
一.这篇随笔来自一道信息论的作业题,因为手动编码过于复杂,所以想到了编程解决,原题目如下图所示: 二.源代码如下: #include <iostream> #include <str ...
- POJ - 1061 青蛙的约会 扩展欧几里得 + (贝祖公式)最小正整数解
题意: 青蛙 A 和 青蛙 B ,在同一纬度按照相同方向跳跃相同步数,A的起点为X ,每一步距离为m,B的起点为Y,每一步距离为 n,一圈的长度为L,求最小跳跃步数. 思路: 一开始按照追击问题来写, ...
- coding++:Arrays.asList() - java.lang.UnsupportedOperationException异常处理
这个异常遇到了才知道坑这么大,坑爹的方法. private String[] otherUserFromArray = new String[]{“3”, “4”, “发放”}; List<St ...
- iOS UmbrellaHeader
Lexical or Preprocessor Issue - Umbrella header for module 'xxx' does not include header 'xxx.h' fra ...
- 17.用cmd创建maven web工程
1.跳转到需要创建maven工程的目录,输入 mvn archetype:generate 2.找到webapp的那一项,输入它的序号(这里是10) 3.输入groupId,artifactId,ve ...
- nginx代理图片访问
nginx代理图片访问 首先配置nginx的代理物理路径 我的是在E盘下面的image 1 #图片的代理 2 server { 3 listen 80; 4 #配置访问的域名 5 server_nam ...