记得网上流传甚广的段子“PHP是世界上最好的语言”,暂且不去讨论是否言过其实,但至少PHP确实有独特优势的,比如它的弱类型,即只需要$符号即可声明变量,使得PHP入手门槛极低,成为大家所青睐的Web服务端语言。那么它的变量是如何实现的呢?我们今天就来学习一下PHP的基本变量。
一、引言
PHP的变量存储在zval结构体中,在执行阶段中编译为op_array时就能看到zval的身影。结构体定义在Zend/zend_types.h中,定义内容如下所示:
struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* 保留字段 */ } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; };二、结构体剖析
2.1、zend_value
结构体的第一个变量是zend_value,顾名思义,它其实也是一个结构体,用于存放变量的值,比如整型、浮点型、引用计数、字符串、数组、对象、资源等。zend_value定义了众多类型的指针,但这些类型并不都是变量的类型,有些是给内核自己使用的,比如指针ast、zv、ptr。
typedef union _zend_value { zend_long lval; /* 整型 */ double dval; /* 浮点型 */ zend_refcounted *counted; /* 引用计数 */ zend_string *str; /* 字符串 */ zend_array *arr; /* 数组 */ zend_object *obj; /* 对象 */ zend_resource *res; /* 资源 */ zend_reference *ref; /* 引用 */ zend_ast_ref *ast; /* 抽象语法树 */ zval *zv; /* zval类型 */ void *ptr; /* 指针类型 */ zend_class_entry *ce; /* class类型 */ zend_function *func; /* function类型 */ struct { uint32_t w1; uint32_t w2; } ww; } zend_value;2.2、u1
u1是一个联合体,它联合了结构体v和整型type_info。下面我们先来看一下结构体v的构成。
union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1;2.2.1、type
type是指变量的类型,刚在2.1中讲到了zend_value是用来存储变量的值,所以也应该有地方存储变量的类型,而这就是type的职责。以下是PHP定义的所有变量类型,有我们熟知的布尔、NULL、浮点、数组、字符串等类型。也有陌生的undef、indirect、ptr类型,变量类型在下一章中详解,这里不再赘述。
/* regular data types */
