小编给大家分享一下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赋值的内部到底经历了怎样的逻辑判断