我们来先看一段代码
$a="string";
$b=&$a;
echo $a;
echo $b;
$b="hello";
echo $b;
echo $a;
unset($b);
echo $b;
echo $a;
?>
输出结果为
string
string
hello
hello
(空)
hello
为什么会输出这样的结果呢?我们来分析一下
首先我们看一下引用类型的结构
struct _zend_reference {
zend_refcounted_h gc;
zval val;
};
我们可以看到,引用类型是一个变量zval和一个zend_refcounted_h组成
先看第一段的
$a="string";
$b=&$a;
echo $a;
echo $b;
执行过程
(gdb) p *z
$1={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=10 '
', type_flags=4 '\004', const_flags=0 '\000', reserved=0 '\000'}, type_info=1034}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
//我们可以看到$a的u1的type为10,所以说明$a已经是引用类型了,对应的内存地址为0x7ffff5a020a8
(gdb) p *$1.value.ref
$2={gc={refcount=2, u={v={type=10 '
', flags=0 '\000', gc_info=0}, type_info=10}}, val={value={lval=17733632, dval=8.7615783471909966e-317,
counted=0x10e9800, str=0x10e9800, arr=0x10e9800, obj=0x10e9800, res=0x10e9800, ref=0x10e9800, ast=0x10e9800, zv=0x10e9800, ptr=0x10e9800, ce=0x10e9800,
func=0x10e9800, ww={w1=17733632, w2=0}}, u1={v={type=6 '\006', type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=6}, u2={
next=28776, cache_slot=28776, lineno=28776, num_args=28776, fe_pos=28776, fe_iter_idx=28776, access_flags=28776, property_guard=28776, extra=28776}}}
//我们可以看到在$a的引用内部 是由gc和val组成,而且val就是一个zval,对应的type是6,字符串类型
(gdb) p *$1.value.ref.val.value.str
$3={gc={refcount=1, u={v={type=6 '\006', flags=7 '\a', gc_info=0}, type_info=1798}}, h=9223378990886268924, len=6, val="s"}
(gdb) p *$1.value.ref.val.value.str.val@6
$4="string"
//对应的打印出ref中的str类型的字符串
(gdb) p z
$5=(zval *) 0x7ffff5a14090
(gdb) p *z
$6={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=10 '
', type_flags=4 '\004', const_flags=0 '\000', reserved=0 '\000'}, type_info=1034}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
//我们可以看到$b的u1的type为10,所以说明$b已经是引用类型了,对应的内存地址为0x7ffff5a020a8 和$a共用一个地址
(gdb) p $6.value.ref
$7=(zend_reference *) 0x7ffff5a020a8
(gdb) p *$6.value.ref
$8={gc={refcount=2, u={v={type=10 '
', flags=0 '\000', gc_info=0}, type_info=10}}, val={value={lval=17733632, dval=8.7615783471909966e-317,
counted=0x10e9800, str=0x10e9800, arr=0x10e9800, obj=0x10e9800, res=0x10e9800, ref=0x10e9800, ast=0x10e9800, zv=0x10e9800, ptr=0x10e9800, ce=0x10e9800,
func=0x10e9800, ww={w1=17733632, w2=0}}, u1={v={type=6 '\006', type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=6}, u2={
next=28776, cache_slot=28776, lineno=28776, num_args=28776, fe_pos=28776, fe_iter_idx=28776, access_flags=28776, property_guard=28776, extra=28776}}}
//$b中的ref也是由gc和zval组成,而且对应的zval中的u1的type为6,是字符串类型
(gdb) p *$6.value.ref.val.value.str
$9={gc={refcount=1, u={v={type=6 '\006', flags=7 '\a', gc_info=0}, type_info=1798}}, h=9223378990886268924, len=6, val="s"}
(gdb) p *$6.value.ref.val.value.str.val@6
$10="string"
//打印出字符串
接下来我们看看
$b="hello";
echo $b;
echo $a;
(gdb) p *z
$11={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=10 '
', type_flags=4 '\004', const_flags=0 '\000', reserved=0 '\000'}, type_info=1034}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
//我们可以看到$b的u1的type为10,所以说明$b已经是引用类型了,对应的内存地址为0x7ffff5a020a8
(gdb) p *$11.value.ref
$12={gc={refcount=2, u={v={type=10 '
', flags=0 '\000', gc_info=0}, type_info=10}}, val={value={lval=140737314679872, dval=6.9533472271273708e-310,
counted=0x7ffff5a5ec40, str=0x7ffff5a5ec40, arr=0x7ffff5a5ec40, obj=0x7ffff5a5ec40, res=0x7ffff5a5ec40, ref=0x7ffff5a5ec40, ast=0x7ffff5a5ec40,
zv=0x7ffff5a5ec40, ptr=0x7ffff5a5ec40, ce=0x7ffff5a5ec40, func=0x7ffff5a5ec40, ww={w1=4121291840, w2=32767}}, u1={v={type=6 '\006',
type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=6}, u2={next=28776, cache_slot=28776, lineno=28776, num_args=28776,
fe_pos=28776, fe_iter_idx=28776, access_flags=28776, property_guard=28776, extra=28776}}}
//$b中的ref是由gc和zval组成,而且对应的zval中的u1的type为6,是字符串类型
(gdb) p *$11.value.ref.val.value.str
$13={gc={refcount=0, u={v={type=6 '\006', flags=2 '\002', gc_info=0}, type_info=518}}, h=9223372247569412249, len=5, val="h"}
(gdb) p *$11.value.ref.val.value.str.val@5
$14="hello"
//打印出对应的字符串
(gdb) p *z
$15={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=10 '
', type_flags=4 '\004', const_flags=0 '\000', reserved=0 '\000'}, type_info=1034}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
//我们可以看到$a的u1的type为10,所以说明$a已经是引用类型了,对应的内存地址为0x7ffff5a020a8 和b一样
(gdb) p *$15.value.ref
$16={gc={refcount=2, u={v={type=10 '
', flags=0 '\000', gc_info=0}, type_info=10}}, val={value={lval=140737314679872, dval=6.9533472271273708e-310,
counted=0x7ffff5a5ec40, str=0x7ffff5a5ec40, arr=0x7ffff5a5ec40, obj=0x7ffff5a5ec40, res=0x7ffff5a5ec40, ref=0x7ffff5a5ec40, ast=0x7ffff5a5ec40,
zv=0x7ffff5a5ec40, ptr=0x7ffff5a5ec40, ce=0x7ffff5a5ec40, func=0x7ffff5a5ec40, ww={w1=4121291840, w2=32767}}, u1={v={type=6 '\006',
type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=6}, u2={next=28776, cache_slot=28776, lineno=28776, num_args=28776,
fe_pos=28776, fe_iter_idx=28776, access_flags=28776, property_guard=28776, extra=28776}}}
//$a中的ref是由gc和zval组成,而且对应的zval中的u1的type为6,是字符串类型
(gdb) p *$15.value.ref.val.value.str
$17={gc={refcount=0, u={v={type=6 '\006', flags=2 '\002', gc_info=0}, type_info=518}}, h=9223372247569412249, len=5, val="h"}
(gdb) p *$15.value.ref.val.value.str.val@5
$18="hello"
打印字符串
接下来我们再来看看
unset(b);echo b;
echo $a;
(gdb) p *z
$1={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=0 '\000', type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=0}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
//大家其实可以看到 在unset($b)的操作过程中,仅仅是把b中的u1的type改为了0,为null类型,其余的地址等信息都未改变,所以对应的$a是不会有任何改变的
所以后面在打印$a的过程中,一切都是正常的,以下为$a的打印过程
(gdb) p *z
$2={value={lval=140737314300072, dval=6.9533472083627576e-310, counted=0x7ffff5a020a8, str=0x7ffff5a020a8, arr=0x7ffff5a020a8, obj=0x7ffff5a020a8,
res=0x7ffff5a020a8, ref=0x7ffff5a020a8, ast=0x7ffff5a020a8, zv=0x7ffff5a020a8, ptr=0x7ffff5a020a8, ce=0x7ffff5a020a8, func=0x7ffff5a020a8, ww={w1=4120912040,
w2=32767}}, u1={v={type=10 '
', type_flags=4 '\004', const_flags=0 '\000', reserved=0 '\000'}, type_info=1034}, u2={next=0, cache_slot=0, lineno=0,
num_args=0, fe_pos=0, fe_iter_idx=0, access_flags=0, property_guard=0, extra=0}}
(gdb) p *$2.value.ref
$3={gc={refcount=1, u={v={type=10 '
', flags=0 '\000', gc_info=0}, type_info=10}}, val={value={lval=140737314679872, dval=6.9533472271273708e-310,
counted=0x7ffff5a5ec40, str=0x7ffff5a5ec40, arr=0x7ffff5a5ec40, obj=0x7ffff5a5ec40, res=0x7ffff5a5ec40, ref=0x7ffff5a5ec40, ast=0x7ffff5a5ec40,
zv=0x7ffff5a5ec40, ptr=0x7ffff5a5ec40, ce=0x7ffff5a5ec40, func=0x7ffff5a5ec40, ww={w1=4121291840, w2=32767}}, u1={v={type=6 '\006',
type_flags=0 '\000', const_flags=0 '\000', reserved=0 '\000'}, type_info=6}, u2={next=28776, cache_slot=28776, lineno=28776, num_args=28776,
fe_pos=28776, fe_iter_idx=28776, access_flags=28776, property_guard=28776, extra=28776}}}
(gdb) p *$2.value.ref.val.value.str
$4={gc={refcount=0, u={v={type=6 '\006', flags=2 '\002', gc_info=0}, type_info=518}}, h=9223372247569412249, len=5, val="h"}
(gdb) p *$2.value.ref.val.value.str.val@5
$5="hello"