变量我们都知道PHP变量是弱类型的,声明的时候不需要指定类型。那么这里是如何实现的呢?这还得从变量的基本结构说起。zval的实现在源代码文件zend_type.h中,可以看到zval的定义:typedefstruct_zval_structzval;struct_zval_struct{zend_valuevalue;/*value*/union{struct{ZEND_ENDIAN_LOHI_4(zend_uchartype,/*activetype*/zend_uchartype_flags,zend_ucharconst_flags,zend_ucharreserved)/*EX(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;}zval结构由一个unionunionzend_value组成,其中保存变量类型的值或指针,两个unionunionu1和u2组成u1u1的作用是存储变量类型和它的信息。里面的字段使用如下:type:记录变量类型,可以通过u2.v.type访问type_flags:对应变量Flags的唯一类型(比如常量类型,需要引用计数的类型,不可变类型),不同类型的变量对应不同的flags。const_flags:常量类型的标志reserved:保留字段u2u2,主要作为辅助功能。由于结构体的内存对齐,u2的空间无论有无u2都已经占据了空间,所以被使用。u2的辅助字段记录了很多类型信息,对内部函数有很大的好处,或者提高缓存友好性或者减少内存寻址操作。这里介绍了其中一些字段。next:用于解决hash冲突问题(hash冲突还未知),记录冲突的下一个元素的位置。cache_slot:运行时缓存。当执行一个函数时,它会先在缓存中查找。如果没有缓存,它会在全局函数表中查找。num_args:函数调用时传入的参数个数access_flags:对象类的访问标志,如publicprotectedprivate。zend_valuetypedefunion_zend_value{zend_longlval;/*整数*/doubledval;/*浮点数*/zend_refcounted*counted;zend_string*str;zend_array*arr;zend_object*obj;zend_resource*res;;zval*zv;无效*指针;zend_class_entry*ce;zend_function*func;结构{uint32_tw1;uint32_tw2;是指向它们各自结构的指针。所以,由于zval的结构,PHP变量在声明的时候不需要显式指定它们的类型,因为无论你给变量赋什么类型的值,它都能帮你找到对应的存储结构。以取值为字符串的变量为例,其结构如下:对比PHP5PHP7中PHP5和PHP7的zval结构,可以看出php7的zval一共只占用了16个字节,而PHP7的zval占用了48个字符通过zval的PHP5部分节省了大量内存。另外,在PHP5中,所有的变量都是在堆中分配的,但是对于临时变量,是不需要在堆中分配的。所以这个在PHP7中做了优化,直接在栈上应用临时变量。常见变量类型下面介绍几种常见类型的变量结构。其他类型可以自行查看源码。整数和浮点数类型对于整数和浮点数类型,由于占用空间小,直接存储在zval中。整数值存储在lval中,浮点值存储在dval中。typedefunion_zend_value{zend_longlval;/*整型*/doubledval;/*浮点类型*/...}stringPHP7定义了一个新的字符串结构。结构如下:struct_zend_string{zend_refcounted_h;zend_ulongh;/*哈希值*/size_tlen;字符值[1];};以上字段的含义:gc:变量引用信息,所有使用引用计数的变量类型都会有这个结构。h:哈希值,计算数组中的索引时会用到。(据说这个操作提高了PHP7的性能5%)len:字符串长度,通过这个值保证二进制安全val:字符串内容,变长struct,分配时根据len长度申请内存数组arrayPHP中非常强大的一种数据结构,它的底层实现是一个普通的有序HashTable,这里简单看一下它的结构。跟进深入。typedefstruct_zend_arrayHashTable;struct_zend_array{zend_refcounted_hgc;union{struct{ZEND_ENDIAN_LOHI_4(zend_ucharflags,zend_ucharnApplyCount,zend_ucharnIteratorsCount,zend_ucharconsistency)}v;uint32_t标志;}你;uint32_tnTableMask;桶*arData;uint32_tnNumUsed;uint32_tnNumOfElements;uint32_tnTableSize;uint32_tnInternalPointer;zend_longnNextFreeElement;dtor_func_tpDestructor;}ObjectPHP7的对象结构也进行了重新设计,与PHP5的实现有很大不同。struct_zend_object{zend_refcounted_hgc;uint32_t句柄;zend_class_entry*ce;constzend_object_handlers*处理程序;哈希表*属性;Class*properties:HashTable结构,key是对象的属性名,value是属性值在properties_tables数组中的偏移量,通过偏移量可以在properties_talbe中找到对应的属性值。properties_talbe[1]:存放对象的属性值ok,先写到这里。参考资料《PHP7 底层设计与源码实现》更多好文,关注公众号获取
