PHP底层变量
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
PHP 中的变量是一些容器,用于存储变量的类型、值、引用此容器的变量的数量以及标志(此变量是否被引用)。
结构体和指针
结构体与类非常相似,但它们不能包含方法,只能包含数据、指向数据的指针和指向函数的指针。在 C 语言中声明结构体时,需要定义其数据类型。定义变量时,可以用结构体的名称代替变量的类型,如下所示:
my_super_struct super_struct_instance;
指针类似于变量,但它们的值存储的是内存中的地址。引用变量的行为类似于解引用的指针,这意味着它们可以访问指针指向的值。我们来看一个例子:
// defining pointer `foo`, that will points to the variable with `int` type
int *foo;
// defining variable with `int` type
int bar = 3;
// taking reference to variable `bar` and assigning it to pointer.
// `foo` stores memory address, where `bar` stores
foo = &bar;
// with an asterisk we dereference the pointer (take the value at its address) and increment the value
(*foo)++;
// we increment the pointer itself, that means the pointer will refer at another value
foo++;
容器
容器是一个名为“Zend value” zval(简称“Zend value”)的结构体,它代表一个任意的 PHP 值,如下所示:
struct zval {
zvalue_value value;
zend_uchar type;
zend_uchar is_ref;
zend_ushort refcount;
};
如我们所见,变量包含值、类型、标志和引用数量。PHPzval支持以下 8 种类型:
BOOLLONG(有符号整数类型)DOUBLE(用于存储浮点数)STRINGARRAYOBJECTRESOURCENULL
zvalue_value是一个联合体union。联合体是一种特殊类型,它可以包含多个不同类型的成员声明,但只会使用其中一个。这就是它的定义:
typedef union _zvalue_value {
long lval; // integer
double dval; // float
struct {
char *val;
int len;
} str; // string
HashTable *ht; // array
zend_object obj; // object
} zvalue_value;
因此,当你创建这种类型的变量时,它将占用与联合体中最重元素占用的内存完全相同的内存。
我们为什么需要这一切?
首先,我们来弄清楚为什么需要引用计数。这很简单:当你将另一个变量的值赋给一个变量时,它们都引用同一个引用zval,并且refcount引用计数会递增。
现在,如果您更改其中一个变量的值,PHP 检测到refcount该值大于 1 后,会复制该变量zval,并在副本中进行更改,这样您的变量就会指向新的值zval。它看起来会像这样:
| PHP | 引擎盖下 |
|---|---|
|
|
|
|
这种技术称为“写时复制”,它可以很好地降低内存消耗。此外,垃圾回收器refcount也需要它,它会从内存中移除所有具有.zvalrefcount = 0
那么引用会发生什么情况?它is_ref是否有效?这很简单:如果您从一个变量创建一个引用,则 is_ref 标志变为 1,并且上述针对此 zval 的优化将不会应用。
| PHP | 引擎盖下 |
|---|---|
|
|
|
|
|
|
文章来源:https://dev.to/larapulse/php-variables-under-the-hood-2onh对 PHP 感兴趣,想了解更多相关内容吗?点击此链接查看更多文章 😉



