当我们在使用PHP定义一个变量时,不需要指定变量类型,并且还可以随意改变变量类型。不免产生疑问,PHP底层的C语言是如何实现的呢?
当我们定义a=1时,源码参考:https://github.com/php/php-src/blob/PHP-5.6.40/Zend/zend.h
$a = 1;
变量名a会存储到全局符号表symbol_table中,符号表的值指向结构体的内存地址,变量的值1存储在这个结构体中
struct _zval_struct {
zvalue_value value; /* 指向_zvalue_value */
zend_uint refcount__gc; /*变量被指向次数,这里是1*/
zend_uchar type; /* IS_LONG */
zend_uchar is_ref__gc;
};
typedef union _zvalue_value {
long lval; /* 1 */
double dval;
struct {
char *val;
int len;
} str;
HashTable *ht;
zend_object_value obj;
zend_ast *ast;
} zvalue_value;
_zval_struct结构体中的type一共有八种类型:IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT、IS_RESPURCE。Zend文件定义如下:
/* data types */
/* All data types <= IS_BOOL have their constructor/destructors skipped */
#define IS_NULL 0
#define IS_LONG 1
#define IS_DOUBLE 2
#define IS_BOOL 3
#define IS_ARRAY 4
#define IS_OBJECT 5
#define IS_STRING 6
#define IS_RESOURCE 7
#define IS_CONSTANT 8
#define IS_CONSTANT_AST 9
#define IS_CALLABLE 10
当把变量a赋值给变量b时
$a = 1;
$b = $a;
符号表新增变量名b,值为上面_zval_struct结构体的内存地址,也就是说并不会产生新的结构体。而是将原有结构体的refcount_gc+1,形成以下结构
{
union zvalue {long 1}
type: is_LONG
refcount_gc:2
is_ref_gc:0
}
当在对修改变量b的值时,就会产生新的结构体,符号表里面b对应的内存地址更新为新的结构体地址。这种只有在改变b的值的时候才会产生新的结构体称为copy on write,在其它语言中也有相似应用。
$a = 1;
$b = $a;
$b = 2;
a{
union zvalue {long 1}
type: is_LONG
refcount_gc:1
is_ref_gc:0
}
b{
union zvalue {long 2}
type: is_LONG
refcount_gc:1
is_ref_gc:0
}