php弱类型的实现
php是一门弱类型的语言,这基本是为人所共知的.但是php是用C语言编写的,C语言是一门强类型的语言,而由C语言开发而来的php没有像C++/Java这些延续C语言的强类型,那php是如何实现这个哪?
PHP在声明和使用变量的时候,并不需要显示的指明其数据类型,这是php弱类型带来的便捷(当然也有性能的损耗),但这并不是说PHP中没有类型的.在PHP中,存在8种变量类型,我们大致可以分为3类
标量类:boolean、integer、float(double)
复合类型:array、object
特殊类型:resource、NULL
上面我们谈了PHP中的类型,只是为了方便我们清楚PHP也是有类型这个概念的.如果我们想要弄清楚上面的问题,那么我们就需要看看PHP是如何实现这些变量的定义和存储的.
变量存储结构
PHP把变量存储到zval结构体中,zval结构体定义在Zend/zend_types.h文件中
typedef struct _zval_struct zval;
不难看出zval实际上面是struct _zval_struct结构体,_zval_struct定义在Zend/zend.h中
struct _zval_struct { /* Variable information */ zvalue_value value; /* value */ zend_uint refcount__gc; zend_uchar type; /* active type */ zend_uchar is_ref__gc; };
PHP使用这个结构体来存储所有用户变量.当然需要注意的是,PHP在存储变量时是存储在PHP用户空间(堆内存中),所以我们在PHP中可以把函数中的变量直接返回.而我们在C语言中有不少变量是声明在栈中的,如果我们直接把变量返回,那么可能会引发stack overflow的,特别是我们这边先接触PHP在回过头来看C的同学特别需要注意.PHP对堆内存有自己的内存管理和垃圾回收机制,所以一般我们PHP程序员大部分都是很少注意内存的消耗的.建议在程序比较占内存的时候,使用unset手动释放内存,这样会减轻服务器的资源压力.
zval结构体中有四个字段,其含义分别为:
属性名 含 义 默 认值
refcount__gc 表示引用计数 1
is_ref__gc 表示是否为引用 0
value 存储变量的值
type 变量具体的类型
目前对我们本文来说涉及到的是value和type,下面我们来看一下这2个字段.
变量类型
zval结构体的type字段就是我们今天问题的关键了,PHP就是通过存储时把字段的类型放在这个type字段里面来实现的弱类型的.type的值可以为: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一.从字面上就很好理解,他们只是类型的唯一标示,根据类型的不同将不同的值存储到value字段。 除此之外,和他们定义在一起的类型还有IS_CONSTANT和IS_CONSTANT_ARRAY。
变量的值存储
看前面在存储时,变量最终是存储在 zvalue_value联合体中的,其定义在Zend/zend.h头文件中.
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object_value obj; zend_ast *ast; } zvalue_value;
这里使用联合体而不是用结构体是出于空间利用率的考虑,因为一个变量同时只能属于一种类型。 如果使用结构体的话将会不必要的浪费空间,而PHP中的所有逻辑都围绕变量来进
行的,这样的话, 内存浪费将是十分大的。这种做法成本小但收益非常大。
PHP正是通过上面几个结构体来实现的弱类型,如果您感觉还有写不清楚,可以看一下<深入理解PHP内核>这本书.
近期评论