首页 > 开发 > Php > 正文

变量在 PHP7 内部的实现(一)

2020-02-18 22:58:04
字体:
来源:转载
供稿:网友
<?php$array = range(0, 1000000);$ref =& $array;var_dump(count($array)); // <-- 这里会进行分离

由于大量的细节描述,本文将会分成两个部分:第一部分主要描述 zval(zend value) 的实现在 PHP5 和 PHP7 中有何不同以及引用的实现。第二部分将会分析单独类型(strings、objects)的细节。

PHP5 中的 zval

PHP5 中 zval 结构体定义如下:

typedef struct _zval_struct { zvalue_value value; zend_uint refcount__gc; zend_uchar type; zend_uchar is_ref__gc;} zval;

如上,zval 包含一个 value、一个 type 以及两个 __gc 后缀的字段。value 是个联合体,用于存储不同类型的值:

typedef union _zvalue_value { long lval;     // 用于 bool 类型、整型和资源类型 double dval;    // 用于浮点类型 struct {     // 用于字符串  char *val;  int len; } str; HashTable *ht;    // 用于数组 zend_object_value obj;  // 用于对象 zend_ast *ast;    // 用于常量表达式(PHP5.6 才有)} zvalue_value;

C 语言联合体的特征是一次只有一个成员是有效的并且分配的内存与需要内存最多的成员匹配(也要考虑内存对齐)。所有成员都存储在内存的同一个位置,根据需要存储不同的值。当你需要 lval 的时候,它存储的是有符号整形,需要 dval 时,会存储双精度浮点数。

需要指出的是是联合体中当前存储的数据类型会记录到 type 字段,用一个整型来标记:

#define IS_NULL     0      /* Doesn't use value */
#define IS_LONG     1      /* Uses lval */
#define IS_DOUBLE   2      /* Uses dval */
#define IS_BOOL     3      /* Uses lval with values 0 and 1 */
#define IS_ARRAY    4      /* Uses ht */
#define IS_OBJECT   5      /* Uses obj */
#define IS_STRING   6      /* Uses str */
#define IS_RESOURCE 7      /* Uses lval, which is the resource ID */
/* Special types used for late-binding of constants */
#define IS_CONSTANT 8
#define IS_CONSTANT_AST 9

PHP5 中的引用计数

在PHP5中,zval 的内存是单独从堆(heap)中分配的(有少数例外情况),PHP 需要知道哪些 zval 是正在使用的,哪些是需要释放的。所以这就需要用到引用计数:zval 中 refcount__gc 的值用于保存 zval 本身被引用的次数,比如 $a = $b = 42 语句中,42 被两个变量引用,所以它的引用计数就是 2。如果引用计数变成 0,就意味着这个变量已经没有用了,内存也就可以释放了。

注意这里提及到的引用计数指的不是 PHP 代码中的引用(使用 &),而是变量的使用次数。后面两者需要同时出现时会使用『PHP 引用』和『引用』来区分两个概念,这里先忽略掉 PHP 的部分。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表