前言工作+实习快一年了,一直从事php后端开发。对于如何提高自己,我一直很迷茫。让我们从php源代码开始。我比较好。这篇文章写的比较仓促,如有错误或遗漏,还望大家指正,多交流才能成长,呵呵。本文主要针对php7,针对php5,可以移步青哥的博客阅读,我看的小菜是本书《php7内核剖析》。接下来,我将使用xdebug来调试php源代码。本文引用了ohmygirl博客的部分内容和代码。本文使用的环境是windows,php7.0.10php7中zval和zend_value的基本结构php7和php5有很多不同,zval和zend_value的结构就是其中之一。在php7中,zval是在zend_types.h中定义的,zval的结构体权重为包含三部分zend_value(存放实际内容),u1和u2两个union,其中u1主要存放以下与变量相关的属性,u2是u1的一些补充。比如在使用数组的时候,会使用Gotou2.next来解决key之后的hash冲突hashstruct_zval_struct{zend_valuevalue;/*存放变量的实际内容*/union{struct{ZEND_ENDIAN_LOHI_4(zend_uchartype,/*存放变量的类型*/zend_uchartype_flags,/*用于标识变量的状态,比如GC管理。通过设置为IS_TYPE_COLLECTABLE,变量将被收集到GC中垃圾回收的buffer缓冲区中*/zend_ucharconst_flags,zend_ucharreserved)/*callinfoforEX(This)*/}v;uint32_t类型信息;}u1;union{uint32_t下一个;/*哈希冲突链*/uint32_tcache_slot;/*文字缓存槽*/uint32_tlineno;/*行号(对于ast节点)*/uint32_tnum_args;/*EX(This)的参数编号*/uint32_tfe_pos;/*foreach位置*/uint32_tfe_iter_idx;/*foreach迭代器索引*/uint32_taccess_flags;/*类常量访问标志*/uint32_tproperty_guard;/*单个属性守卫*/uint32_textra;/*没有进一步说明*/}u2;};zend_uchartype:以下为外部使用的变量类型#defineIS_UNDEF0#defineIS_NULL1#defineIS_FALSE2#defineIS_TRUE3#defineIS_LONG4#defineIS_DOUBLE5#defineIS_STRING6#defineIS_ARRAYfine7#defineIS_OBJECT8#IS_RESOURCE9#defineIS_REFERENCE10php7中zend_value结构typedefunion_zend_value{zend_longlval;/*长值*/doubledval;/*双精度值*/zend_refcounted*counted;/*用于统计计数??,*/zend_string*str;zend_array*arr;zend_object*obj;zend_resource*res;zend_reference*ref;zend_ast_ref*ast;zval*zv;无效*指针;zend_class_entry*ce;zend_function*func;结构{uint32_tw1;uint32_tw2;zval中:(1)zend_uchartype这个用来表示当前变量(比如$a)是什么类型的变量($a是string类型?还是int类型?还是引用类型....)inzend_value:(1)zend_refcounted*计数;表示引用计数的个数,什么是引用计数?它是zend_value变量被zval引用的次数。比如我们的$a=“abcs”;$c=$a;$b=$a;此时counted=3,如下图,其中refcount也是GC自动回收内存的依据。下面将详细讲解php7变量的内部实现。php7中变量的实现分为以下几种方式(1)。对于boolen类型,还有null和undefined,它们没有具体的值,只有类型,直接在zval中根据zend_uchar类型的类型判断,不用引用计数正是因为它不是应用计数来实现的,所以它的refcount为0(2)对于int类型和float类型,因为zend_value中有zend_long和double来存储数据,如下图,所以不需要重新赋值如果使用引用计数,直接在副本中赋值即可。这样可以省去很多引用计数相关的操作。定义一个$a=1,php内核中zval和zend_value的关系(三)第三种是常规变量,使用引用计数定义。在这些变量的实现中,它们都是通过指针指向特定的数据类型。例如:zend_string*str;struct_zend_string{zend_refcounted_hgc;zend_ulongh;/*哈希值*/size_tlen;字符值[1];};$假设我定义了一个$a="111";它的内部实现是,注意这里zend_string中的charval[1],主要是因为C语言中的string以“0”结尾,所以zend_string中$a=变量值“111”的存储是charval[4]=“111”。php7中的赋值1.普通赋值前面说过,在PHP中,定义一个变量$a="444",其实会生成一个zval和一个zend_value,然后zval指向这个zend_value,实现对$a="444"定义的配对,然后使用refcount来计算引用的数量。**所以可以得出refcount表示当前有多少个zval指向同一个zend_value**我们定义如下:$a="111";$b=$a;当然还有int,double,null之类的变量boolean,都是直接通过zval保存的,不会共享一个zend_value,所以直接使用深拷贝。至于什么是深拷贝,什么是浅拷贝,最直接的区别就是是否重新生成一个相同的zend_value。具体请参考深拷贝和浅拷贝。后续赋值(COWcopyonwrite)将使用深拷贝。对于php的赋值,其实并不是所有的类型都是一样的。刚才说了,在php的zval中有一个特殊的字段,用来标识当前类型适合于哪种形式。zend_uchar类型标志,|重新计算|收藏|可复制|不可变的----------------+------------+----------------+----------+------------简单类型||||字符串|×||x|实习字符串||||数组|×|×|x|不可变数组||||x对象|×|×||资源|×|||参考|×||它主要用于内存管理。有关详细信息,请参阅内存管理。2.php中的引用赋值就是我们常用的引用,比如$a=&$b,像这样。在php7中实现引用时,在php中实现引用时,会先生成一个zend_reference类型,在这个类型中嵌套了一个zval,然后这个zval的zend_value会指向前一个zval的zend_value,原来的那个zval类型转换为IS_REFERENCE类型。简单的说就是将原来的zval类型转换为IS_REFERENCE,生成一个新的zend_reference类型指向zend原来的zend_value。(真是jb,久违了)。struct_zend_reference{zend_refcounted_hgc;zvalval;};比如我们定义一个$a="1111";$b=&$a;它的变换如下图所示$a="111"$b=&$a;可能有朋友注意到zend_reference中的refcount是2,但是最后真正的zend_value是refcount1,这是为什么呢?其实很好理解。前面说了refcount表示有多少个zvals指向了zend_value,而zend_reference中只有一个zval指向了zend_value。中间加一层zend_reference其实有很多好处。这样可以保持原来的zend_value类型不变,为深拷贝操作提供拷贝条件。下面举个例子,看看是不是一目了然。只能说那些开发内核的神牛太牛逼了。......当然,php中的值传递不止这么简单,还有很多复杂的东西。好久没看到了。希望大家不要喷php中的COW(copyonwrite)copy-on-write。优化方法,这里涉及到深拷贝和浅拷贝的知识,请移步。关于深拷贝,上面的例子很好地说明了所谓深拷贝就是将原始数据拷贝到一个独立分配的地址空间中。Assignmentonwrite是对deepcopy的一种优化,也就是说deepcopy只有在写操作发生的时候才进行。例如:$a="3333";$b=$a;$b.="444";$a="3333";$b=$a;这个操作会导致两个zval指向同一个zend_value,这里不会触发COW,当$b.="444"时会执行deepcopy;发生写操作,触发COW,进行深拷贝,复制完全相同的zend_value,$b所在的zval会从原来的$a所在的zval指向前一个zend_value,转换为指向copiednewzend_valueifnotdeep如果你复制,那么when$b.="444";执行后,$a也将等于“3333444”。当然,并不是所有的zend_value类型都可以复制。这个可以参考我之前的zend_uchartype_flagstable**一文中可能存在的不足之处,还请大家指正。本来打算写GC回收原理的,但是已经2点多了,23333333,明天继续码字。......不好意思**下一篇要写关于数组在php中的实现;电梯需要艺术,我需要女孩本文参考http://bbs.csdn.net/topics/39...http://blog.csdn。net/black_ox...http://blog.csdn.net/xiaolei1...https://segmentfault.com/a/11...https://github.com/laruence/p...https://www.cnblogs.com/ohmyg...可能有遗漏的参考博客,希望博主见谅
