$i = 1; //int $i = 'show me the money'; //string $i = 0.02; // float $i = array(1, 2, 3); // array $i = new Exception('test', 123); // object $i = fopen('/tmp/aaa.txt', 'a') // resource如果你对弱类型原理理解不深刻,在变量比较时候,会出现“超出预期”的惊喜。
$str1 = null; $str2 = false; echo $str1==$str2 ? '相等' : '不相等'; $str3 = ''; $str4 = 0; echo $str3==$str4 ? '相等' : '不相等'; $str5 = 0; $str6 = '0'; echo $str5==$str6 ? '相等' : '不相等';
typedef struct _zval_struct { zvalue_value value; /* 变量的值 */ zend_uint refcount__gc; /* 引用计数器 */ zend_uchar type; /* 类型 */ zend_uchar is_ref__gc; /* 是否是引用 */ } zval;
属性名 | 含义 | 默认值 |
---|---|---|
refcount__gc | 表示引用计数 | 1 |
is_ref__gc | 表示是否为引用 | 0 |
value | 存储变量的值 | |
type | 变量具体的类型 |
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; /* this will always be set for strings */ } str; /* string (always has length) */ HashTable *ht; /* an array */ zend_object_value obj; /* stores an object store handle, and handlers */ } zvalue_value;布尔型,zval.type=IS_BOOL,会读取zval.value.lval字段,值为1/0。如果是字符串,zval.type=IS_STRING,会读取zval.value.str,这是一个结构体,存储了字符串指针和长度。
如果是NULL,只需要zval.type=IS_NULL,不需要读取值。 通过对zval的封装,PHP实现了弱类型,对于ZE来说,通过zval可以存取任何类型。
typedefstruct_zend_rsrc_list_entry { void *ptr; int type; int refcount; }zend_rsrc_list_entry;
其中,ptr是一个指向资源的最终实现的指针,例如一个文件句柄,或者一个数据库连接结构。type是一个类型标记,用于区分不同的资源类型。refcount用于资源的引用计数。
内核中,资源类型是通过函ZEND_FETCH_RESOURCE数获取的。
ZEND_FETCH_RESOURCE(con, type, zval *, default, resource_name, resource_type);
<? php $var = fopen('/tmp/aaa.txt', 'a'); // 资源 #1 $var = (int) $var; var_dump($var); // 输出1 ?>
5.3 标准类型与复杂类型转换
void convert_to_long(zval* pzval) |
void convert_to_double(zval* pzval) |
void convert_to_long_base(zval* pzval, int base) |
void convert_to_null(zval* pzval) |
void convert_to_boolean(zval* pzval) |
void convert_to_array(zval* pzval) |
void convert_to_object(zval* pzval) |
void convert_object_to_type(zval* pzval, convert_func_t converter) |
宏 | 访问变量 |
Z_LVAL(zval) | (zval).value.lval |
Z_DVAL(zval) | (zval).value.dval |
Z_STRVAL(zval) | (zval).value.str.val |
Z_STRLEN(zval) | (zval).value.str.len |
Z_ARRVAL(zval) | (zval).value.ht |
Z_TYPE(zval) | (zval).type |
Z_LVAL_P(zval) | (*zval).value.lval |
Z_DVAL_P(zval) | (*zval).value.dval |
Z_STRVAL_P(zval_p) | (*zval).value.str.val |
Z_STRLEN_P(zval_p) | (*zval).value.str.len |
Z_ARRVAL_P(zval_p) | (*zval).value.ht |
Z_OBJ_HT_P(zval_p) | (*zval).value.obj.handlers |
Z_LVAL_PP(zval_pp) | (**zval).value.lval |
Z_DVAL_PP(zval_pp) | (**zval).value.dval |
Z_STRVAL_PP(zval_pp) | (**zval).value.str.val |
Z_STRLEN_PP(zval_pp) | (**zval).value.str.len |
Z_ARRVAL_PP(zval_pp) | (**zval).value.ht |
Zend/zend_globals.h
struct _zend_executor_globals { //略 HashTable symbol_table;//全局变量的符号表 HashTable *active_symbol_table;//局部变量的符号表 //略 };
在写PHP扩展时候,可以通过EG宏来访问PHP的变量符号表。EG(symbol_table)访问全局作用域的变量符号 表,EG(active_symbol_table)访问当前作用域的变量符号表,局部变量存储的是指针,在对HashTable进行操作的时候传递给相 应函数。
<? php $temp = 'global'; function test() { $temp = 'active'; } test(); var_dump($temp); ?>
创 建函数外的变量$temp,会把这个它加入全局符号表,同时在全局符号表的HashTable中,分配一个字符类型的zval,值为‘global‘。创 建函数test内部变量$temp,会把它加入属于函数test的符号表,分配字符型zval,值为’active' 。
#define MAKE_STD_ZVAL(zv) ALLOC_ZVAL(zv);INIT_PZVAL(zv) #define ALLOC_ZVAL(z) ZEND_FAST_ALLOC(z, zval, ZVAL_CACHE_LIST) #define ZEND_FAST_ALLOC(p, type, fc_type) (p) = (type *) emalloc(sizeof(type)) #define INIT_PZVAL(z) (z)->refcount__gc = 1;(z)->is_ref__gc = 0;
MAKE_STD_ZVAL(foo)展开后得到:
(foo) = (zval *) emalloc(sizeof(zval)); (foo)->refcount__gc = 1; (foo)->is_ref__gc = 0;
宏 | 实现方法 |
ZVAL_NULL(pvz) | Z_TYPE_P(pzv) = IS_NULL |
ZVAL_BOOL(pvz) |
Z_TYPE_P(pzv) = IS_BOOL; Z_BVAL_P(pzv) = b ? 1 : 0; |
ZVAL_TRUE(pvz) | ZVAL_BOOL(pzv, 1); |
ZVAL_FALSE(pvz) | ZVAL_BOOL(pzv, 0); |
ZVAL_LONG(pvz, l)(l 是值) |
Z_TYPE_P(pzv) = IS_LONG; Z_LVAL_P(pzv) = l; |
ZVAL_DOUBLE(pvz, d) |
Z_TYPE_P(pzv) = IS_DOUBLE; Z_LVAL_P(pzv) = d; |
ZVAL_STRINGL(pvz, str, len, dup) |
Z_TYPE_P(pzv) = IS_STRING; Z_STRLEN_P(pzv) = len; if (dup) { {Z_STRVAL_P(pzv) =estrndup(str, len + 1);} }else { {Z_STRVAL_P(pzv) = str;} } |
ZVAL_STRING(pvz, str, len) | ZVAL_STRINGL(pzv, str,strlen(str), dup); |
ZVAL_RESOURCE(pvz, res) |
Z_TYPE_P(pzv) = IS_RESOURCE; Z_RESVAL_P(pzv) = res; |