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 ...
随机推荐
- Java-方法(新手)
//创建的一个类.public class zy1ri0319 { //公共静态的主方法. public static void main(String[] args){ //调用方法. zy1(); ...
- Asp.Net Core 中IdentityServer4 实战之 Claim详解
一.前言 由于疫情原因,让我开始了以博客的方式来学习和分享技术(持续分享的过程也是自己学习成长的过程),同时也让更多的初学者学习到相关知识,如果我的文章中有分析不到位的地方,还请大家多多指教:以后我会 ...
- docker-ce 在windows10下使用volume的注意事项
最近想搭建一套CI/CD环境尝试一下,因为手里云服务太小了(1C1G),撑不起来gitlab和jenkins.恰巧年前配了台高配版的windows机器,就想在家里的机器上通过docker装gitlab ...
- Linux 基础篇(二)
1.linux 关机和重启 关机: shutdown -h 10:20 # 指定时间关机 shutdown -h now # 马上关机 shutdown -h +10 # 10分钟后关机 ...
- django缓存和跨域解决和短信验证码的使用
缓存 在实际项目中,存在大量的数据检索,比如我们刷微博的时候,刚开始加载速度慢一点,然后第一次加载完毕之后,如果你此时的手机没有网络,但是你发现你的微博还是可以照样刷,但是刷到一定的页面就走不动了,那 ...
- java后台调用文件上传接口
借鉴:https://blog.csdn.net/yjclsx/article/details/70675057 /** * 调用流程上传文件接口上传文件 * @param url * @param ...
- Redis学习笔记2-redis管道(pipeline)
redis的管道(Pipelining)操作是一种异步的访问模式,一次发送多个指令,不同步等待其返回结果.这样可以取得非常好的执行效率.这就是管道,调用方法如下: 来源:http://blog.csd ...
- 在Ubuntu中安装OpenCV-Python | 三
在本教程中,我们将学习在Ubuntu System中设置OpenCV-Python.以下步骤针对Ubuntu 16.04和18.04(均为64位)进行了测试. 可以通过两种方式在Ubuntu中安装Op ...
- HDU - 2444 二分图最大匹配 之 判断二分图+匈牙利算法
题意:第一行给出数字n个学生,m条关系,关系表示a与b认识,判断给定数据是否可以构成二分图,如果可以,要两个互相认识的人住一个房间,问最大匹配数(也就是房间需要的最小数量) 思路:要看是否可以构成二分 ...
- Jmeter接口测试之参数传递(十三)
在接口自动化测试中,经常会遇到的一种场景就是参数的场景,比如在用户列表中获取所有的用户列表,然后获取到某一个用户的ID,查看该用户的详细信息.首先在这里理清思路,它的流程是,首先获取到数据,然后在Jm ...