深入理解PHP7内核之Reference

本文地址:http://www.laruence.com/2018/04/08/3179.html

PHP7以后我们把(REFERENCE)变成了一种新的类型:IS_REFERNCE. 然而引用是一种很常见的应用, 所以这个变化带来了很多的变化, 也给我们在做PHP7开发的时候, 因为有的时候疏忽忘了处理这个类型, 而带来不少的bug.

最简单的情况, 就是在处理各种类型的时候, 从此以后我们要多考虑这种新的类型, 比如在PHP7中, 这样的代码形式就变得很常见了:

try_again:

swtich(Z_TYPE_P(zv)){

caseIS_TRING:

break;

caseIS_ARRAY:

break;

...

caseIS_REFERENCE:

zv=Z_REFVAL_P(zv);//解引用

gototry_again;

break;

}

如果大家自己写的扩展, 如果忘了考虑这种新的类型, 那么就会导致问题.

为什么?

那么既然这种新类型会带来这么多问题, 那么当时为什么要用把引用变成一种类型呢? 为什么不还是使用一个标志位呢?

一句话来说, 就是我们不得不这么做. -_#

前面说到, Hashtable直接存储的是zval, 这样在符号表中, 俩个zval如何共用一个数值呢? 对于字符串等复杂类型来说还好, 我们貌似可以在zend_refcounted结构中加入一个标志位来表明是引用来解决, 然而这个也会遇到Change On Write带来的复制, 但是我们知道在PHP7中, 一些类型是直接存储在zval中的, 比如IS_LONG, 但是引用类型是需要引用计数的, 那么对于一个是IS_LONG并且又是IS_REFERNCE的zval该如何表示呢?

所以对于IS_LONG的引用来说, 就用一个类型是IS_REFERNCE的zval, 它指向一个zend_reference, 而这个zend_reference->val中是一个类型为IS_LONG的zval.

Change On Write

PHP采用引用计数来做简单的垃圾回收, 考虑如下的代码:

1.$val="laruence";

2.$ref=&$val;

3.$copy=$val;

?>

$ref和$val是指向同一个zval的引用, 在PHP5的时候, 我们是通过一个引用计数为2, 并且引用标志位为1来表示这种情况, 当把$val复制给$copy(line 3)的时候, 我们发现$val是一个计数大于1的引用, 所以要产生Change on write, 也就是分离. 所以我们需要复制这个zval.

从而这就很好的解决了上一章所说的PHP5的那个经典的问题, 比如我们在PHP7下运行上一章的那个问题, 我们得到的结果是:

$ php-7.0/sapi/cli/php /tmp/1.php

Used 0.00021380008539

Used 0.00020173048281

可见确实没有发生复制, 从而不会产生任何的性能问题.

如果你想和更多PHP大神交流,添加下方微信号,拉你入群

如果你想获得更多学习资料,添加下方微信号,送你资源

关注菲菲

带你入群,带你学习

更有资源免费送!

COME BABY

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181018A0W9IM00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券