美文网首页
php内核分析:变量分离/引用

php内核分析:变量分离/引用

作者: 奋斗live | 来源:发表于2019-06-16 18:10 被阅读0次
一、回顾变量结构

在了解php内核是如何进行变量分离和引用的时候,我们要提前了解变量的结构体,如下
zval是_zval_struct结构体的别名

 typedef struct _zval_struct zval;

_zval_struct 结构体

 struct _zval_struct {
    /* Variable information */
    zvalue_value value;  /* 变量值保存在这里 12字节*/
    zend_uint refcount;//4字节,变量引用计数器
    zend_uchar type;   /* active type变量类型 1字节*/
    zend_uchar is_ref;//是否变量被&引用,0表示非引用,1表示引用,1字节
    };

_zvalue_value结构体

 typedef union _zvalue_value {
    long lval;      /* long value */
    double dval;    /* double value */
    struct {
    char *val; //4字节
    int len;   //4字节
    } str;
    HashTable *ht;    /* hash table value */
    zend_object_value obj;
 } zvalue_value;
二、refcount和is_ref

这两个字段对于php的变量分离和引用,起着至关重要的作用,也包括了php的内存回收,下面我们就围绕这两个字段进行学习

is_ref 的意思,就是标记变量是否为引用变量。如果是普通变量则为0,引用变量则为1
refcount 记录了当前zval被引用的次数

三、实例

接下来我们来看一段简单的代码

<?php
   $age = "yilian";
   $num = $age;
?>

正如上面所说,像这么段代码,
1、首先创建了字符变量,申请了7个字节的内存,分别保存 yilian 和 NULL(\0)的结尾
2、第二行重新定义一个新字符,并"复制"了变量age的值给变量num
分析:
以上这个,php是在symbol_table中存储了一个值age,对应这个指针是指向一个zval结构体,变量值"yilian",就存在这个zval中,上面这个因为,age和num,是同一个值,其实并非是申请了两个空间,而是通过指针指向同一个zval来实现的。避免了内存空间的浪费。

<?php
   $age = "yilian";//创建了个age变量。此时保存这个zval的refcount为1
   debug_zval_dump($age);
   $num = $age;//创建了个新的变量,变量指向刚才创建的age,把zval的refcount加1,变为2
   debug_zval_dump($age);
?>

以上这段代码打印结果如下


image.png

分析:
可能你会发现,以上打印结果和代码里面的分析的refcount的值不同,这是因为debug_zval_dump导致的,这其中也涉及到了变量的传参,导致传入到debug_zval_dump的时候,又加了一次1,所以是 2和3

<?php
   $age = "yilian";
   $num = $age;
   debug_zval_dump($num);
?>

<?php
   $age = "yilian";
   $num = $age;
   unset($age);
   debug_zval_dump($num);
?>

以上打印,分别输出如下


image.png image.png

通过以上可知道,当unset的时候,zval被引用的次数将会被减少1

<?php
   $age = "yilian";
   $num = $age;
   $age = 1;
   debug_zval_dump($num);
?>

这个打印效果如下


image.png

这和上面相比,refcount也减少了1
分析:
这个就是写时复制机制
php在修改一个变量前,会先查看这个变量的引用计数,也就是refcount的值,是否大于1,如果是大于1,就会执行一个分离的过程,如上,php执行赋值1的时候,,查看到refcount大于1,就会复制一个新的zval出来。并且把原先的val的refcount减1,并修改symbol_table,age就指向这个新的zval结构,num指向原来的zval结构。

<?php
   $age = "yilian";
   $num = &$age;
   $age = 1;
  
?>

以上这段将导致num的值也变为1,
分析:
当执行到第二行的时候,$age对应的zval的refcount变为2,并且把is_ref置为1,
第三行的时候,会判断is_ref是否为1 如果是1则不分离,所以age和num还是同一个zval,

<?php
   $age = "yilian";
   $num = $age;//refcount为2
  $sex = &$age;//因为refcount大于1,执行分离,并把refcount减1,然后将age和sex关联
?>

所以以上这个age和sex的refcount为1
逻辑类似如下

if((*val)->is_ref || (*val)->refcount<2){
          //不执行分离
        ... ;//process
  }
<?php
   $age = "yilian";//refcount为1
   $num = &$age;//不分离,refcount加1,把is_ref置为1,并把age和num代表的zval进行关联
   debug_zval_dump($age);
?>

不过有个奇怪的地方,这里打印出来的age,refcount为1,这是为什么呢?

分析:
因为当执行debug_zval_dump(age)的时候,age会以传值得方式传递给debug_zval_dump,此参数不是引用传递,是引用变量分离,所以debug_zval_dump收到的参数age已经和原来的age、num进行分离了,所以变成了1

相关文章

  • php内核分析:变量分离/引用

    一、回顾变量结构 在了解php内核是如何进行变量分离和引用的时候,我们要提前了解变量的结构体,如下zval是_zv...

  • PHP——2(PHP变量作用域)

    PHP——2(PHP变量作用域)PHP——3(PHP变量分离/引用(Variables Separation))为...

  • PHP——3(PHP变量分离/引用(Variables Sepa

    PHP——2(PHP变量作用域)PHP——3(PHP变量分离/引用(Variables Separation))为...

  • PHP——4(PHP赋值行为)

    PHP——2(PHP变量作用域)PHP——3(PHP变量分离/引用(Variables Separation))为...

  • PHP——1(PHP变量的存储结构)

    PHP——2(PHP变量作用域)PHP——3(PHP变量分离/引用(Variables Separation))为...

  • php基础知识面试点

    引用变量考察点 回顾真题什么是引用变量?在php中,用什么符号定义引用变量? 考点分析分析:考官考点PHP引用变量...

  • PHP垃圾回收机制

    垃圾的产生 之前的文章已经介绍过PHP的引用计数机制-PHP内核探索之变量-理解引用,当变量赋值、传递时并不会直接...

  • php写时复制

    写时复制原理 : php变量发生赋值之前会检查变量引用数量, 若引用量>1则复制多一份变量用于和之前的变量进行分离...

  • 1、php引用变量

    1、PHP引用变量: 引用: Zval: 引用:recommend 画图分析法 关于引用的unset: 结果还是1...

  • 2. php基础-引用变量的考点

    引用变量的考点 真题: 什么是引用变量? 在PHP当中,用什么符号定义引用变量? 考点:PHP的引用变量的概念及定...

网友评论

      本文标题:php内核分析:变量分离/引用

      本文链接:https://www.haomeiwen.com/subject/bsygfctx.html