加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

php指针 PHP7之变量底层实现

发布时间:2022-12-21 13:33:18 所属栏目:PHP教程 来源:网络
导读: 数据类型是一个语言最为基础的部分,它是高级语言抽象出来的一个概念,对于低级的语言来说是没有这个概念的,比如机器语言。对内存,CPU而言并没有什么类型之分,内存中的数据是没有差别的

数据类型是一个语言最为基础的部分,它是高级语言抽象出来的一个概念,对于低级的语言来说是没有这个概念的,比如机器语言。对内存,CPU而言并没有什么类型之分,内存中的数据是没有差别的,高级语言为内存中这些无差异的数据指定了特定的计算方式,比如读取一个32位整型,就是告诉CPU按照整型的规则连续读取4个字节的数据。

数据类型的产生使得程序的编写更加规范,简洁,灵活,它是现代高级语言必不可少的一部分。与强类型语言不同,PHP中变量的数据类型并不是固定不变的,它可以根据不同的使用场景进行转化。

变量

变量是最常见的数据类型应用形式,它由三个主要部分组成:变量名,变量值,变量类型,PHP中变量名与变量值可以简单的对应为:zval,zend_value,这两个概念一定要区分开。

PHP中通过$符号定义一个变量,在定义的同时可以进行初始化,在变量使用前不需要提前声明。事实上普通变量定义的方式包含了两步:变量定义,变量初始化,只定义而不初始化变量也是可以的,比如:

$a;  
$b=1;

这段代码在执行时会分配两个zval,也就是这里定义了两个变量,只不过$a没有值而已,相当于unset()了。

变量类型

PHP中的变量类型,也就是数据类型,宏观角度可分为以下8种。

具体到内部实现上会细分出更多的类型,比如布尔型在内部实际分为IS_TRUE,IS_FALSE

两种,也有一些基于基础数据类型产生的特殊类型,比如引用。全部类型如下:

#define IS_UNDEF
#define IS_NULL
#define IS_FALSE
#define IS_TRUE
#define IS_LONG
#define IS_DOUBLE
#define IS_STRING
#define IS_ARRAY
#define IS_OBJECT
#define IS_RESOURCE
#define IS_REFERENCE
#define IS_CONSTANT
#define IS_CONSTANT_AST
#define _IS_BOOL
#define IS_CALLABLE
#define IS_INDIRECT
#define IS_PTR

内部实现

PHP中通过zval这个结构体来表示一个变量,而不同类型的变量值则通过zval嵌入的一个联合体表示,即zend_value,通过zval,zend_value及不同类型的结构实现了PHP基础的数据类型。

typedef struct _zval_struct   zval;
struct _zval_struct {
     //变量值
     zend_value    value;
     union {
        struct {
               ZEND_ENDIAN_LOHI_4(
                //变量类型
                zend_uchar  type,
                //类型掩码,各类型会有几种不同的几种属性,内存管理会用到
                zend_uchar  type_flags,
                zend_uchar  const_flags,
                //预留字段,zend执行过程中会用来记录call info
                zend_uchar   reserved)
        } v;
        uint32_t type_info;
} u1;
union {
      uint32_t  var_flags;
      uint32_t  next;
      uint32_t  cache_slot;
      uint32_t  lineno;
      uint32_t  num_args;
      uint32_t  fe_pos;
      uint32_t  fe_iter_idx;
} u2; //一些辅助值
};

zval除了嵌入了一个zend_value用来保存具体的变量值,还有两个特殊的union;

zend_value的结构比较简单,它是一个联合体,各类型根据自己的类型选择使用不同的成员,其中整型,浮点型的值直接存储在zend_value中,其他类型则是指针,指向具体类型的结构。

typedef union  _zend_value {
   zend_long         lval;       //整型
   double            dval;       //浮点型
   zend_refcounted   *counted;   //获取不同类型结构的gc头部
   zend_string       *str;       //string字符串
   zend_array        *arr;       //array数组
   zend_object       *obj;       //object对象
   zend_resource     *res;       //resource资源类型
   zend_reference    *ref;       //引用类型
   zend_ast_ref      *ast;       //下面几个都是内核使用的value
   zval              *zv;        //指向另一个zval
   void              *ptr;       //指针,通用类型
   zend_class_entry  *ce;        //类
   zend_function     *func;      //函数
   struct {
      uint32_t  w1;
      uint32_t  w2;
   } ww;
}  zend_value;

zend_value中定义了众多类型的指针,这些类型并不全是变量的类型,有些类型只给内核自己使用,比如ast,ptr,zv等。

字符串

PHP中并没有使用char来表示字符串,而是为了字符串单独定义了一个结构:zend_string。

在zend_value中通过str指向具体的结构,zend_string除了字符串内容,还存储了其他几个信息,具体结构如下:

typedef struct  _zend_string  zend_string;
struct _zend_string {
       zend_refcounted_h  gc;
       zend_ulong         h;
       size_t             len;
       char               val[1];
};

该结构有4个成员。

zend_string的几个成员含义都比较直观,比较特殊的是用于存储字符串内容的成员,这里并没有使用char类型,而是使用了一个可变数组val。val[1]并不表示它只能存储一个字节,在字符串分配时实际上是类似这样操作的:malloc(sizeof(zend_string)+字符串长度),也就是会多分配一些内存,而多出的这块内存的起始位置就是val,这样就可以直接将字符串内容存储到val中,通过val进行读取。如果val是一个指针char*php指针,则需要额外分配一次内存,变长结构不仅可以节省一次内存分配,而是更有助于内存管理,free时直接释放zend_string即可。

(编辑:源码网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!