PHP变量在内核中的存储方式

PHP是弱类型语言,也就是说一个PHP变量可以保存任何的数据类型。但是PHP是使用C语言编写的,而C语言是强类型的语言,每个变量都有固定类型,不能随意改变变量的类型(可以通过强类型转换改变,不过有可能出现问题),在Zend引擎中是怎么做到一个变量保存任何的数据类型呢?

打开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;

struct _zval_struct {
    /* Variable information */
    zvalue_value value;     /* value */
    zend_uint refcount__gc;
    zend_uchar type;    /* active type */
    zend_uchar is_ref__gc;
};

zval结构体就是通常用到的PHP变量(如$variable)在内核中的表示方式。在zval结构体中,可以看到4个成员变量,分别是

  • zvalue_value value : 变量的值,PHP变量的值就保存在这里。
  • zend_uint refcount__gc : 变量引用数,变量引用计算器。
  • zend_uchar type;zend_uchar type : 变量的类型。
  • zend_uchar is_ref__gc : 变量是否被引用。

zval结构体的value成员变量是一个zvalue_value联合体,PHP能够保持任何的结构类型就是因为这个联合体。从zvalue_value联合体的成员变量中可以看到,不同的类型会保存到不同的成员变量中,这样就实现了PHP变量可以存储任何数据类型。例如,当变量是整数类型时,会保存到value的lval成员变量中;当变量的类型是字符串时,又会保存到value的str成员变量中。如下表展示了不同类型保存到对应的成员变量中。

PHP语言层类型保存在zvalue_value的成员变量
long,bool,resourelval
doubledval
stringstr(len保存字符串的长度,val保存字符串的值)
arrayht
objectobj

现在已经解决了一个PHP变量可以保存任意类型的问题,但是另一个问题又出现了,就是Zend引擎是怎么知道这个变量保存的是什么类型呢?我们注意到,zval结构体中有个type成员变量,这个成员变量就是保存一个PHP变量的类型。

Zend引擎定义了几种变量类型,如下:

#define IS_NULL     0
#define IS_LONG     1
#define IS_DOUBLE   2
#define IS_BOOL     3
#define IS_ARRAY    4
#define IS_OBJECT   5
#define IS_STRING   6
#define IS_RESOURCE 7

每一个宏定义对应PHP语言层的一种类型,例如当zval的type成员变量等于IS_STRING时(zval.type==IS_STRING),说明这个变量的类型时字符串类型。

宏定义表示类型
IS_NULLNULL类型(null)
IS_LONG整数类型(int)
IS_DOUBLE浮点类型(float)
IS_STRING字符串类型(string)
IS_ARRAY数组类型(array)
IS_OBJECT对象类型(object)
IS_BOOL布尔类型(bool)
IS_RESOURCE资源类型(resource)

可以通过下面的代码打印一个zval的类型:

switch(zval.type) {
    case IS_NULL:
        php_printf("zval type is null\n");
        break;
    case IS_STRING:
        php_printf("zval type is string\n");
        break;
    case IS_LONG:
        php_printf("zval type is long\n");
        break;
    case IS_ARRAY:
        php_printf("zval type is array\n");
        break;

    ...
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值