侧边栏壁纸
博主昵称
流苏小筑

步伐虽小,密而不止

PHP底层原理之:变量及数据结构(下篇)

2023年02月04日 89阅读 0评论 0点赞

PHP底层原理之:变量及数据结构(下篇)

上篇说到写时复制,本篇继续

7.传值引用

思考1:下面代码,两者是否共享一个结构体,如果是,和传值赋值有什么不同?

<?php

$a = 3;
$b = &$a;
echo $a . '---' . $b;
echo "\r\n";

$b = 5;
echo $a . '---' . $b;

不是共享,是共用,两个变量都有对此内存的结构体的操作资格。跟传值赋值的区别是,两个变量直接指向同一块内存,而且修改时不会发生延迟复制。
1.当$b = &$a时,两个变量都指向同一块内存,refcount_gc加1,并且,is_ref_gc = 1,表示是引用关系。
m4dpfo1q.png

2.当修改$b = 5时,由于is_ref_gc = 1,表明此内存的结构体与对应变量时引用关系,所以直接修改此结构体的值。
m4dpg2zr.png

传值赋值与引用赋值的区别
需要注意的是,写时复制与引用机制是不同的概念。写时复制在赋值时使用延迟复制,而引用则直接让两个变量指向同一块内存,且不会有延迟复制的操作。

  • 写时复制:赋值时内存共享,但修改时才会复制。
  • 引用:多个变量指向同一块内存,任何修改都会影响所有引用。

8.强制分裂

<?php

  $a = 3;
/**
 * $a => {
 *     value : 3
 *     refcount_gc: 1
 *     if_ref_gc:0
 * }
 */


$b = $a;
/**
 * $a,$b => {
 *     value : 3
 *     refcount_gc: 2
 *     if_ref_gc:0
 * }
 */

$c = &$a;
/** 思考:此时是否会改成如下结构?
 * {
 *     value : 3
 *     refcount_gc: 3
 *     if_ref_gc:1
 * }
 *
 * 不会,否则$b将会受到影响。
 * 如果is_ref_gc 由0->1的过程,refcount_gc > 2,说明此时有多个变量共享此内存,
 * 不能直接引用,此时就会发生强制分裂。复制一份$a给$b
 *
 * $b => {
 *      value : 3
 *      refcount_gc: 1
 *      if_ref_gc:0
 * }
 *
 * 完后再修改原结构体,以及建立引用关系
 * $a,$c = {
 *       value : 3
 *       refcount_gc: 2
 *       if_ref_gc:1
 *  }
 */

$c = 5;
echo $a, $b, $c; // 输出 5 3 5 

9.引用数组时的怪现象

回忆之前的代码,数组的值存储的是一个指向哈希表的地址,而不是具体的值。

HashTable *ht;  

思考1:下面代码中,$tmp是否会受到影响

<?php

$arr = [0, 1, 2, 3];
$tmp = $arr;
$arr[1] = 11;
echo $tmp[1];

不会,此时会正常写时复制。

m4dpgmil.png

但注意当$arr[1]修改时,$tmp会有一个新的结构体,但是除了$tmp[1]会指向新的内存地址,数组中其他的值还是指向原结构体的zval对应地址。
m4dphoo2.png

思考2:下面代码,是否会影响$tmp?

<?php

$arr = [0, 1, 2, 3];
$x = &$arr[1];
$tmp = $arr;
$arr[1] = 100;
$arr[2] = 100;
echo $tmp[1];

哈希表内部的$arr[1]已经改为引用关系:is_ref_gc = 1,外部还不知道,此时发生写时复制,复制一份$arr给$tmp,但里面的小单元1是引用关系,所有$arr[1]和$tmp[1]此时都指向同意内存地址。所以会影响到$tmp[1];
m4dpi8xj.png
m4dpid3l.png

10.循环数组时的怪现象

1.数组尽量避免使用引用
2.foreach后,不会重置数组内部指针,使用数组是,不要假想指针正好指向数组头部,可以在foreach后rest一下数组。

11.符号表与作用域

t函数在执行时,根据函数的参数,局部变量等,生成一个执行环境的结构体函数编译后的opcode,称为op_parrray(就是执行逻辑),开始执行--以入栈的环境结构体为环境来执行。并生成此函数的符号表,函数找变量,就在符号表找,即局部变量。
注意:1个函数可能调用多次,栈中可能有某函数的多个执行环境入栈,但这个函数的op_array只有1个。
m4dptodg.png

0

—— 评论区 ——

昵称
邮箱
网址
取消