本篇文章基于PHP的commit为:9fa1d1330138ac424f990ff03e62721120aaaec3
在PHP内核里面,有一个叫做SEPARATE_ARRAY的宏。长这样:
| 1 | 
 | 
一句话来说,这个宏做的事情就是分离zend_array。我们知道,PHP是通过引用计数来管理多个变量对数组的引用,如果其中一个变量需要去修改数组的内容,那么底层就会单独为这个变量分配一个新的zend_array,并且原来的zend_array的引用计数减一。然后,SEPARATE_ARRAY做的事情就是这个。
因为PHP底层实在是有太多需要修改数组的操作了,所以我们确实需要SEPARATE_ARRAY来帮助我们去分离数组。
除此之外,我们会在zend_hash.c文件的所有写数组的函数里面发现HT_ASSERT_RC1这个断言宏。这个宏对于写C扩展的我们来说,在debug上是非常的有帮助的。我们来看看HT_ASSERT_RC1这个宏:
| 1 | 
 | 
首先,这个宏只会在PHP开启debug的时候才会起作用。
然后,我们发现,这个断言宏能够成功的情况有两个。一个是设置了zend_array的HASH_FLAG_ALLOW_COW_VIOLATION标志;第二个是zend_array的引用计数是1。我们先来说一下第二点,因为第一点和第二点有关系。
为什么zend_array的引用计数要是1?
因为PHP扩展操作数组的函数没法对数组进行分离。我们知道,如果修改一个数组,是需要发生写时复制的(我们也可以叫做写时分离),如果不进行写时复制,那么就会导致其他引用了这个数组的变量出问题(可能这是一个你意想不到的修改)。所以,只要这个数组的引用计数是1,我们就可以确定,这个数组只有一个变量在引用,所以我们可以放心的去修改它了。
那么,如果我们非要在引用计数大于1的时候去修改这个数组呢?那么第一种情况就起作用了,我们可以设置HASH_FLAG_ALLOW_COW_VIOLATION这个标志(翻译过来就是允许违反写时复制),来强制不遵守写时复制的规则。
 
         
              