程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> PHP基礎知識 >> PHP源碼 — 變量

PHP源碼 — 變量

編輯:PHP基礎知識
 

變量是一切系統和語言的基礎。

變量是簡單的。

當然哲學告訴我們事物必然要從簡單發展到復雜、再次發展到簡單。

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";  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved