php进阶(一)php变量类型及存储

  如大家众所周知,php支持的数据类型有int、float、string、bool、array、object、resource、null八种数据类型,php是弱类型语言,在声明变量时,并不需要指定变量类型,在实际使用变量时,才会确定变量类型。在这篇文章中,一起和大家学习一下php语言的底层变量存储结构,从而深入的理解php是如何实现弱类型语言的。

  1、变量的结构  

  变量的值存储到以下所示zval结构体中。 zval结构体定义在Zend/zend.h文件,其结构如下:

typedef struct _zval_struct zval;
...
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在存储变量时将变量类型也保存在同一个结构体中。这样我们就能通过这些信息获取到变量的类型。

  zval结构体中有四个字段,其含义分别为:

属性名含义默认值
refcount__gc 表示引用计数 1
is_ref__gc 表示是否为引用 0
value 存储变量的值  
type 变量具体的类型

  type的值可以为: IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT和IS_RESOURCE 之一  

2、变量类型

  前面提到变量的值存储在zvalue_value联合体中,结构体定义如下:

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;
} zvalue_value;

  这里使用联合体而不是用结构体是出于空间利用率的考虑,因为一个变量同时只能属于一种类型。 如果使用结构体的话将会不必要的浪费空间,而PHP中的所有逻辑都围绕变量来进行的,这样的话, 内存浪费将是十分大的。这种做法成本小但收益非常大。

  • 字符串String

  字符串类型的存储结构是一个结构体,其中多了一个字串长度的字段,len这是典型的以空间换时间的做法,获取到字符串长度的时间复杂度是O(1)

  

struct {
    char *val;
    int len;
} str;
  • 数组array

  数组是PHP中最常用,也是最强大变量类型,它可以存储其他类型的数据,而且提供各种内置操作函数。数组的存储相对于其他变量要复杂一些, 数组的值存储在zvalue_value.ht字段中,它是一个HashTable类型的数据。 PHP的数组使用哈希表来存储关联数据。哈希表是一种高效的键值对存储结构。PHP的哈希表实现中使用了两个数据结构HashTable和Bucket。 PHP所有的工作都由哈希表实现,在下节HashTable中将进行哈希表基本概念的介绍以及PHP的哈希表实现。

  • 对象Object

  在面向对象语言中,用户可以自定义所需要的类结构,包括类的属性,方法等数据。对象是类的一个具体实现。对象中保存着自身的状态和所能完成的操作。php的对象是一种复合型的数据,使用一种zend_object_value的结构体来存放。其定义如下

  

typedef struct _zend_object_value {
    zend_object_handle handle;  //  unsigned int类型,EG(objects_store).object_buckets的索引
    zend_object_handlers *handlers;
} zend_object_value;

  PHP的对象只有在运行时才会被创建,前面的章节介绍了EG宏,这是一个全局结构体用于保存在运行时的数据。 其中就包括了用来保存所有被创建的对象的对象池,EG(objects_store),而object对象值内容的zend_object_handle域就是当前 对象在对象池中所在的索引,handlers字段则是将对象进行操作时的处理函数保存起来

  

posted on 2020-12-17 19:27  1450811640  阅读(354)  评论(0编辑  收藏  举报