栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

跟厂长学PHP7内核(七):常见变量类型的基本结构

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

跟厂长学PHP7内核(七):常见变量类型的基本结构

上篇文章讲述了变量的存储结构zval,今天我们就来学习一下几个常见变量类型的基本结构。

一、类型一览

zval中的u1.v.type用来存储变量的类型,而zval.value存储的是不同类型对应的值,所以type决定value取值的地方,以下是PHP7所定义的所有类型。

#define IS_UNDEF		0   
#define IS_NULL			1   
#define IS_FALSE		2   
#define IS_TRUE			3   
#define IS_LONG			4   
#define IS_DOUBLE		5   
#define IS_STRING		6   
#define IS_ARRAY		7   
#define IS_OBJECT		8   
#define IS_RESOURCE		9   
#define IS_REFERENCE	10  


#define IS_ConSTANT		11  
#define IS_CONSTANT_AST	12  


#define _IS_BOOL		13
#define IS_CALLABLE		14


#define IS_INDIRECT     15  
#define IS_PTR			17  
  • IS_UNDEF:标记未定义,表示数据可以被覆盖或删除。
  • IS_TRUE/IS_FALSE:本来在PHP5中统一用IS_BOOL来代替,这里分成两个可以避免一次类型的检查。
  • IS_REFERRENCE:引用类型,用于处理PHP脚本中的符号&。
  • IS_PTR:用来解析value.ptr,通常用在函数类型上,比如声明一个函数或方法。
  • IS_INDIRECT:用于解决在全局符号表访问CV变量的问题。

二、不同类型的结构

刚才聊到zval.u1.v.type决定了zval.value,下面来看一下zend_value结构体的定义。

typedef union _zend_value {
	zend_long  lval;				
	double     dval;				
	zend_refcounted  *counted;   
	zend_string      *str;
	zend_array*arr;
	zend_object      *obj;
	zend_resource    *res;
	zend_reference   *ref;
	zend_ast_ref     *ast;
	zval      *zv; 
	void      *ptr;
	zend_class_entry *ce; 
	zend_function    *func;      
	struct {
		uint32_t w1;
		uint32_t w2;
	} ww;
} zend_value;

基本可以看出该结构体的变量和上文定义的类型是一一对应的,我们抽取几个常用的类型讲述一下。

2.1、字符串

字符串str对应的结构体是zend_string,它有四个成员,定义如下。

struct _zend_string {
	zend_refcounted_h gc;
	zend_ulong h;  
	size_t     len;
	charval[1];
};
  • gc:变量的引用计数信息,用于内存管理。
  • h:字符串通过Time33算法计算的到的Hash值,避免了在数组操作中hash值的重复计算,据说提高了PHP7百分之5的性能。
  • len:字符串的长度。
  • val:字符串的内容,val[1]并不表示只能存储1个字节,在字符串分配时实际上是操作了malloc(sizeof(zend_string)+字符串你长度),也就是会多分配一些内存,而多出来的内存起始位置就是val,这样就可以将字符串直接存储到val,并通过val进行读取,这种采用了柔性数组的方式,读写效率更高。

2.2、数组

成员变量arr对应的结构体是zend_array,它就是你可能有所耳闻的HashTable,zend_array结构体定义如下。

struct _zend_array {
	zend_refcounted_h gc;
	union {
		struct {
			ZEND_ENDIAN_LOHI_4(
				zend_uchar    flags,
				zend_uchar    nApplyCount,
				zend_uchar    nIteratorsCount,
				zend_uchar    reserve)
		} v;
		uint32_t flags;
	} u;
	uint32_t   nTableMask;
	Bucket    *arData;
	uint32_t   nNumUsed;
	uint32_t   nNumOfElements;
	uint32_t   nTableSize;
	uint32_t   nInternalPointer;
	zend_long  nNextFreeElement;
	dtor_func_tpDestructor;
};
  • nTableMask:根据key的hash code映射元素存储位置时有用到,它的值是nTableSize的负数,nTableMask=-nTableSize。
  • arData:数组的每一个元素都保存在这里,默认指向第一个元素。
  • nNumUsed:当前使用的Bucket数,但不都是有效的,因为有的Bucket虽然被unset了但是没有马上被删除,而是做了IS_UNDEF标记。
  • nNumOfElements:有效的Bucket数,这个就与上面不同了,这里记录的是真实有效的Bucket数量。
  • nTableSize:数组的总容量。
  • nIternalPointer:当前遍历的指针。
  • nNextFreeElement:下一个索引的值,比如每次给数组新增数据时,该值就会加一,$a[] = 1。
  • pDestructor:析构函数,在删除或覆盖某个元素时,调用该函数,可以对旧元素进行清理。
  • u:这里的u主要还是起到辅助作用,比如flags用来设置散列表的一些属性是否持久化、是否已经初始化等。

2.3、对象
struct _zend_object {
	zend_refcounted_h gc;
	uint32_t   handle;
	zend_class_entry *ce;
	const zend_object_handlers *handlers;
	HashTable *properties;
	zvalproperties_table[1];
};
  • gc:引用计数。
  • handle:一次请求期间对象的编号,每一个对象都有一个唯一的编号,与创建的先后顺序有关,主要是在垃圾回收的时候使用。
  • ce:该对象所属的类。
  • handlers:对象操作的处理函数,比如成员属性的读写、成员方法的获取、对象的销毁克隆等。
  • properties:普通成员属性的哈希表,初始化对象时该值为NULL。
  • properties_table:用来存储普通成员的属性值,对象对非静态成员属性的操作就是通过这个数组。

参考文献
  • 《PHP7内核剖析》
  • 《PHP7底层设计与源码实现》

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号