PHP赋值的内部到底经历了怎样的逻辑判断

  介绍

小编给大家分享一下PHP赋值的内部到底经历了怎样的逻辑判断,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获、下面让我们一起去了解一下吧!

<强>前言

在PHP中,一个变量被赋值,内部到底经历了怎样的逻辑判断呢?

在PHP内核中是通过zval这个结构体来存储变量的,它的定义在Zend/Zend。h文件里

struct  _zval_struct  {zvalue_value 价值;,/*,变量的值,*/zend_uint  refcount__gc; zend_uchar 类型;,/*,变量当前的数据类型,*/zend_uchar  is_ref__gc;}; typedef  struct  _zval_struct  zval;//在Zend/zend_types.h里定义的:typedef  unsigned  int  zend_uint; typedef  unsigned  char  zend_uchar;

使用xdebug的xdebug_debug_zval函数可以打印出变量的refcount, is_ref的值。

a 美元;=,& # 39;Hello  & # 39;; b 美元;=,一美元;

以上内容在内核中怎么执行呢?

 zval  * helloval; MAKE_STD_ZVAL (helloval); ZVAL_STRING (helloval,“Hello  World",, 1); zend_hash_add(如(active_symbol_table),“a",, sizeof (“a"), helloval,, sizeof (zval *), NULL); ZVAL_ADDREF (helloval);,//这句很特殊,我们显式的增加了helloval结构体的refcountzend_hash_add(如(active_symbol_table),“b",, sizeof (“b"), helloval,, sizeof (zval *), NULL); 

可以看出来,当变量赋值的时候,其实两个变量指向的是同一个地址空间,那么问题来了,如果指向同一个地址空间,那不是修改a, b也会跟着改变。这就涉及php的写时复制机制。以上代码,如果后面一行为$ b=& # 39; 123 & # 39;判断过程如下:

  • 如果这个变量的zval部分的refcount小于2,代表没有别的变量在用,则直接修改这个值

  • 否则,复制一份zval 的值,减少原zval的refcount的值,初始化新的zval的refcount,修改新复制的zval

简单变量

先引用赋值后普通赋值

var_dump(memory_get_usage());$a = '1234567890';xdebug_debug_zval('a');var_dump(memory_get_usage());$b = &$a;xdebug_debug_zval('a','b');var_dump(memory_get_usage());$c = $a;xdebug_debug_zval('a','b','c');var_dump(memory_get_usage());$a = '1234567890';var_dump(memory_get_usage());$b = &$a;var_dump(memory_get_usage());$c = $a;

输出内容如下:

int(121672)
a: (refcount=1, is_ref=0)='1234567890'

int(121776)
a: (refcount=2, is_ref=1)='1234567890'
b: (refcount=2, is_ref=1)='1234567890'

int(121824)
a: (refcount=2, is_ref=1)='1234567890'
b: (refcount=2, is_ref=1)='1234567890'
c: (refcount=1, is_ref=0)='1234567890'

int(121928)

$a 赋值,开辟了104byte空间,变量a refcount=1,is_ref=0

$b 赋值,开辟了48byte空间,变量a refcount=2,is_ref=1。48byte是符号表占用,a,b执行同一个地址空间

$c 赋值,开辟了104byte空间。由于a,b是引用,所以在c赋值的时候,会开辟新空间,复制a zval内容,并初始化refcount,is_ref,所以a 的refcount不变,c 的refcount=1

先普通赋值后引用赋值

var_dump(memory_get_usage());$a = '1234567890';xdebug_debug_zval('a');var_dump(memory_get_usage());$b = $a;xdebug_debug_zval('a','b');var_dump(memory_get_usage());$c = &$a;xdebug_debug_zval('a','b','c');var_dump(memory_get_usage());

输出内容如下:

int(121672)

a: (refcount=1, is_ref=0)='1234567890'
int(121776)

a: (refcount=2, is_ref=0)='1234567890'
b: (refcount=2, is_ref=0)='1234567890'
int(121824)

a: (refcount=2, is_ref=1)='1234567890'
b: (refcount=1, is_ref=0)='1234567890'
c: (refcount=2, is_ref=1)='1234567890'
int(121928)

$a 赋值,开辟了104byte空间,变量a refcount=1,is_ref=0

$b 赋值,开辟了48byte空间,变量a refcount=2,is_ref=1。48byte是符号表占用,a,b指向同一个地址空间

$c 赋值,开辟了104byte空间。由于a,c是引用,需要与b隔离开来,因此会赋值原有的zval,初始化zval,将a,c指向新复制的zval,同时原有的zval refcount-1

数组

$arr = [0=>'one'];
  xdebug_debug_zval (& # 39; arr # 39;);
  美元的arr [1],=, arr美元;
  
  xdebug_debug_zval (& # 39; arr # 39;);
  
  美元的arr [2],=, arr美元;
  xdebug_debug_zval (& # 39; arr # 39;);
  设置(arr[1]美元);
  xdebug_debug_zval (& # 39; arr # 39;);
  设置(arr[2]美元);
  xdebug_debug_zval (& # 39; arr # 39;); 

PHP赋值的内部到底经历了怎样的逻辑判断