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 ...
随机推荐
- Spring框架——IOC 工厂方法
IoC 是典型的⼯厂模式,如何使⽤用⼯厂模式创建 bean, IoC 通过⼯厂模式创建 bean 有以下两种⽅式 xml <?xml version="1.0" encodi ...
- 工作中常用到的Java集合类有哪些?
前言 只有光头才能变强. 文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y Java集合是我认为在Java基础中最最重要的知 ...
- 简单BBS项目开始(一)
1.BBS需求分析和创建ORM 1. 需要哪些表 1. UserInfo 1. username 2. password 3. avatar #头像图片 2. 文章表: title publish_d ...
- Python中保留两位小数的几种方法
https://blog.csdn.net/Jerry_1126/article/details/85009810 保留两位小数,并做四舍五入处理方法一: 使用字符串格式化>>> a ...
- python之面向对象函数与方法,反射,双下方法
一.函数和方法 1.函数和方法的区别 函数: 全都是显性传参,手动传参,与对象无关 方法: 存在隐性传参,与对象有关 1.1通过函数名可以判断 len()就是函数 str.count()就是方法 de ...
- Transformers 词汇表 | 二
作者|huggingface 编译|VK 来源|Github 词汇表每种模型都不同,但与其他模型相似.因此,大多数模型使用相同的输入,此处将在用法示例中进行详细说明. 输入ID 输入id通常是传递给模 ...
- POJ-3134-Power Calculus(迭代加深)
题意:输入一个n,问x从1次方开始,到n次方 ,可以乘或除已经计算出来的数 ,最少需要执行多少步? 思路:迭代加深 ,深度从0开始 ,直到返回值为真. 在深搜过程中剪枝(深度的判断 ,当前最大值尽全力 ...
- 负载均衡器nginx和ribbon区别
1,nginx 是服务器端的负载均衡器,所有请求发送到nginx之后,nginx通过反向代理的功能分发到不同的服务器,做负载均衡 2,ribbon是客户端的负载均衡器,他是通过将eureka注册中心上 ...
- Python基础 | pandas中dataframe的整合与形变(merge & reshape)
目录 行的union pd.concat df.append 列的join pd.concat pd.merge df.join 行列转置 pivot stack & unstack melt ...
- VS2015 远程调试:Remote Debugger
一.关于Remote Debugger 使用VS远程调试器Remote Debugger,我们可以调试部署在不同机器上的应用程序,如桌面应用程序和Asp.Net应用程序. 二.Remote Debug ...