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

php指针 PHP7之变量底层实现

发布时间:2022-12-21 11:18:56 所属栏目: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即可。
 

(编辑:开发网_新乡站长网)

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