今天绝对是兴奋的一天,不单单是周五这个特殊的日子(周六日能够休息啦),也不是弄清了某wordpress插件的功能流程,更不是再次买到了想吃好久的手撕牛肉,而是真正解决了一直以来(嘿嘿,其实时间不长)对PHP中变量引用和函数传参的疑惑。 php
故事源于一个巧合,我在查PHP变量做用域的东西时看到的文章(后面再附上地址,无心侵权做者大大)。由于这篇只讲变量和函数传参的,因此其余的不涉及了(也无力涉及哈哈)。 html
看这么一句 wordpress
$a = 'abc';
当咱们定义一个变量时,PHP会为咱们作两件事情 函数
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount; zend_uchar type; /* active type */ zend_uchar is_ref; };这个就是zval的C语言定义,在PHP中变量都是用这个结构体来存储,其中成员zvalue_value是一个联合体,用以存储底层强类型变量,这种结构也是实现PHP弱类型的关键,在这里只须要清楚有这么个结构体就能够了。
$a = 12; $b = $a;
执行到第二句时,会在symbol_table中新加入b,令b指向a所指向的那个zval结构体,这个zval的refcount加1, 到这根据以往的知识可能就有疑问了,b指向a指向的结构体不就是引用了嘛,再看下面代码: ui
$a = 12; $b = &$a;
那这算什么?执行第二句时,除了在symbol_table中加入b令其指向a指向的那个zval并使refcount加1外,还会改变该zval中is_ref值为1(默认为零应该),is_ref是个bool值,用来标识这个变量是不是属于引用集合(reference set),这样这个zval就与一开始不太同样了。 spa
来看更复杂的: .net
$a = 12; $b = $a; $c = &$a;
前两行执行完与前面第一个例子是同样的,此时$a和$b指向的zval的refcount值为2,is_ref为0,表示有两个symbol指向这个zval, is_ref为0,表示zval不属于引用集合,当第三行执行时时,发现zval的refcount不为1且不是引用集合,那么便为$b复制一个zval结构体,同时$a的zval的refcount减1,又由于多了$c指向原来的zval,因此又refcount加1,仍是2,同时$a也是$c的zval的is_ref置1,表示这个zval属于引用集合了,$b的zval则是新的zval(refcount=1,is_ref=0)。 插件
第二、3行交换位置最后的结果相同,只不过zval的变化顺序不一样,最终仍然是$a与$c指向同一个zval(refcount=2,is_ref=1),$b指向的zval(refcount=1,is_ref=0)。 code
再有$d、$e等原理同样。 orm
当更改变量时也会发生zval的新建与变化,原理同上,不细讨论了,可参见:
当咱们明白了这个机制的时候,函数传参就迎刃而解了:
$a = 12; function change($k){ $k = 1; } change(&$a); //至关于$k = &$a,接下来就知道怎么办了吧,$a的值是能够改变的 change($a); //至关于$k = $a,你看,还用我说么?好的,到这就差很少了,要是我写的有点乱很差懂(不是深奥,我有自知之明的),好好研究下上面两个网址。
恩,这篇写的好累,休息休息