變量是一切系統和語言的基礎。
變量是簡單的。
當然哲學告訴我們事物必然要從簡單發展到復雜、再次發展到簡單。
PHP 中定義變量非常的簡單只用了一個包含4個成員的變量 _zval_struct
struct _zval_struct {
zvalue_value value;/* value */
zend_uint refcount__gc;
zend_uchar type;/* active type */
zend_uchar is_ref__gc;
};
先說說這四個成員變量的作用
/*存放變量的值*/
zvalue_value value;
/*變量引用計數*/
zend_uint refcount__gc;
/* 變量類型*/
zend_uchar type;
/*是否強制引用標記*/
zend_uchar is_ref__gc;
zvalue_value value; 數據結構
typedef union _zvalue_value {
long lval;/* long value */
double dval;/* double value */
struct {
char *val;
int len;
} str;
HashTable *ht;/* hash table value */
zend_object_value obj;
zend_ast *ast;
} zvalue_value;
變量的定義,並且賦值。
<?php
$a=”hello a”;
?>
源碼實現:
/*
定義部分
*/
Zval *z_a;
MAKE_STD_ZVAL(z_a);
/*
變量賦值
*/
ZVAL_STRING(z_a, "hello a", 0);
/*
保存到全局變量表中,這個時候才有變量名字叫$a
*/
ZEND_SET_SYMBOL(EG(active_symbol_table), "a", z_a);
MASK_STD_ZVAL 函數宏定義
#define MAKE_STD_ZVAL(zv) \
ALLOC_ZVAL(zv); \
INIT_PZVAL(zv);
其實是申請一塊內存
(p) = (type *) emalloc(sizeof(type))
申請完內存,進行cow的前置操作
#define INIT_PZVAL(z) \
(z)->refcount__gc = 1; \
(z)->is_ref__gc = 0;
引用計數初始化為1,強制引用初始化為0
可以通過xdebug 來檢測
<?php
xdebug_debug_zval('a');
?>
情況如下:
(refcount=1, is_ref=0),string ’1′ (length=1)
前面我們以ZVAL_STRING 字符串定義為例子
#define ZVAL_STRING(z, s, duplicate) { \
const char *__s=(s); \
Z_STRLEN_P(z) = strlen(__s); \
Z_STRVAL_P(z) = (duplicate?estrndup(__s, Z_STRLEN_P(z)):(char*)__s);\
Z_TYPE_P(z) = IS_STRING; \
}
所以我建議在使用 ZVAL_STRING(z_a, “hello a”, 0);
estrndup 函數原型
ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
char *p;
p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
if (UNEXPECTED(p == NULL)) {
return p;
}
memcpy(p, s, length);
p[length] = 0;
return p;
}
可以看出是通過 _emalloc 去申請 length +1 的內存長度。
變量查找
PHP的內核數據結構嚴格意義上說其實只有一種就是hashTable。所以變量的檢查/檢索就是hashtable的檢索。
ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData)
這幾方法我們來拆分下
zend_hash_find(那個hashTable,查找的名字,名字的程度,zval* 這個數據結構去存放);
例子:
zval **z_a;
if (zend_hash_find(EG(active_symbol_table),
"a", sizeof("a"),
(void**)&z_a) == SUCCESS)
{
php_printf("$a");
}
else
{
php_printf("$a is not defined.");
}
變量內存使用
PHP 的變量是存放在symbol_table中。
我們通過memory_get_usage 看下內存使用情況
<?php
var_dump(memory_get_usage(TRUE));
$a = "hello a";
var_dump(memory_get_usage(TRUE));
?>
int 262144
int 262144
都是 262144,難道沒有用到內存?
當然這是因為PHP 在啟動的時候會向系統申請一定的內存,後面變量的一切內存操作都是PHP向系統申請的這塊內存區域進行操作。
再看個例子:
<?php
var_dump(memory_get_usage());
$a = "hello a";