解析PHP底层内核源码之变量
更新时间:2023-10-25PHP底层内核源码之变量
在PHP中,变量是程序中存储数据的基本单元,这些数据可以是数字、字符串、数组、对象或者资源等类型。PHP底层内核源码中对变量的定义、初始化、垃圾回收和传递等操作进行了详细的实现。下面将从这些方面介绍PHP底层内核源码中变量的实现。
变量的定义
在PHP中,定义变量时需要指定变量类型,以下是一些常见的变量类型定义:
int $i; float $f; string $s; bool $b; array $a; object $obj; resource $res;
定义变量时需要为其分配内存空间,这个过程在Zend/zend_alloc.c文件的_zend_mm_alloc函数中完成,如下代码所示:
ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size, int permanent) { void *ptr = zend_mm_alloc_heap(heap, size, permanent); if (ptr == NULL && !permanent) { ptr = zend_mm_alloc_heap(heap, size, 1); if (ptr != NULL) { permanent = 1; } } if (ptr == NULL) { zend_mm_alloc_failure(size, permanent); } ZEND_MM_CHECK_MAGIC((char*)ptr-sizeof(zend_mm_hdr),) return ptr; }
该函数根据指定大小size在内存池heap中分配内存空间,并返回指向该空间的指针。需要注意的是,指向变量的指针并不是变量本身,变量在内存中对应的位置可能比指针所指向的位置向前或向后偏移。
变量的初始化
在PHP中,变量可以先定义再初始化,也可以在定义变量时就进行初始化。对于已经定义的变量,可以通过赋值语句进行初始化,如下所示:
$i = 10; $s = 'hello world'; $a = array(1, 2, 3);
PHP中的变量默认值为NULL,如果一个变量未被初始化,那么它的值就是NULL。在PHP底层内核源码中,变量的初始化是由init_zval函数完成的,如下代码所示:
ZEND_API void init_zval(zval *z) { Z_TYPE_INFO_P(z) = IS_NULL; Z_RES_P(z) = NULL; Z_ARRVAL_P(z) = NULL; Z_OBJ_P(z) = NULL; Z_STR_P(z) = NULL; Z_UNUSED_P(z) = 0; Z_LVAL_P(z) = 0; Z_DVAL_P(z) = 0; }
该函数将zval结构体中各个成员的值都初始化为0,即将变量的类型设置为IS_NULL,关联数组和对象销毁时需要用到的成员指针设置为NULL,字符串和资源的成员指针也都设置为NULL。虽然在PHP代码中,变量默认值为NULL,但是在实现上还是通过init_zval函数进行空间的初始化。
变量的垃圾回收
PHP底层内核源码中的垃圾回收主要是在zval结构体中完成的,zval结构体是PHP中变量的底层实现。在PHP中,垃圾回收是一种自动管理内存的方式,它可以自动检测不再使用的内存空间,并将其释放。PHP的垃圾回收机制主要有两种:
- 引用计数
- 标记清除
PHP底层内核源码中采用的是引用计数的方式来进行垃圾回收。在PHP代码中,变量赋值是按值传递的,因此多个变量可能指向同一块内存空间。通过增加和减少zval结构体的refcount计数器,可以实现对内存空间的引用计数统计和管理。当refcount为0时,代表该内存空间已经没有任何变量引用,此时就可以将该空间回收,如下是PHP内核源码中实现引用计数回收的核心代码片段:
void _zval_dtor(zval *zval_ptr ZEND_FILE_LINE_DC) { switch (Z_TYPE_P(zval_ptr)) { case IS_RESOURCE: { ... break; } case IS_OBJECT: { ... break; } case IS_ARRAY: { ... FREE_HASHTABLE(Z_ARRVAL_P(zval_ptr)); Z_ARRVAL_P(zval_ptr) = NULL; break; } case IS_STRING: { ... free_string(Z_STR_P(zval_ptr)); Z_STR_P(zval_ptr) = NULL; break; } default: { break; } } Z_TYPE_P(zval_ptr) = IS_NULL; Z_COUNTED_P(zval_ptr) = 0; }
该函数用于销毁zval结构体,当其中某个变量的refcount为0时就执行实际的销毁操作。根据变量的类型,该函数分别调用不同的销毁函数。对于数组、字符串等,销毁函数会先释放其对应的空间,然后将zval结构体的成员指针设置为NULL,防止在回收悬空指针。销毁操作完成后,还要将zval结构体的类型设置为IS_NULL,同时将其refcount清零。
变量的传递
在PHP底层内核源码中,变量的传递是按值传递的,因此传递过程是将变量的值复制一份到新的内存空间中,传递新的内存空间指针。在PHP中,对于数组和对象等复杂类型,传递的是它们的引用地址,一旦传递过程中发生了修改,那么原变量的值也会受到影响。
总结:本文从PHP底层内核源码的角度详细介绍了变量的定义、初始化、垃圾回收和传递等操作。我们了解到变量是程序中存储数据的基本单元,定义变量时需要为其分配内存空间。变量的默认值为NULL,在初始化过程中会调用init_zval函数将其初始值设置为NULL。PHP底层内核源码中采用的是引用计数的方式进行垃圾回收,zval结构体的refcount计数器用于实现引用计数统计和管理,当refcount为0时,代表该内存空间已经没有任何变量引用,此时就可以将该空间回收。变量的传递是按值传递的,像数组和对象等复杂类型传递的是其引用地址。对于PHP开发人员来说,了解变量在底层是如何实现和管理的,对于我们写出高效稳定的代码有重要帮助。