PHP原始碼分析 變數的儲存方式

2021-07-02 01:36:51 字數 3131 閱讀 1346

分類: c/c++

php 2011-12-09 17:16

1683人閱讀收藏 

舉報php

儲存zend

string

table

struct

php中的變數型別和值是通過c語言實現的,核心具體是如何組織使用者在php中定義的變數呢?

hashtable在ze核心中被廣泛使用,php變數也正是儲存在乙個hashtable實現的符號表裡。

當在php中呼叫乙個函式或者類時,核心會建立乙個新的符號表,這也是為什麼在函式中無法使用函式外部定義的變數的原因。(因為他們分屬兩個符號表,乙個當前作用域,乙個全域性作用域)

現在來看核心中是如何定義作用域的:

[cpp]view plain

copy

struct

_zend_executor_globals ;  

可以通過eg巨集來訪問變數符號表,eg(symbol_table)訪問全域性作用域的變數符號表,eg(active_symbol_table)訪問當前作用域的變數符號表。

[php]view plain

copy

<?php  

$foo

='bar'

;  ?>  

上面這段**很簡單,建立變數foo,並賦值bar。之後的php**中就可以呼叫$foo變數了。

現在看看php中定義的變數,核心中是如何實現的。偽**:

[cpp]view plain

copy

zval* foo;  

make_std_zval(foo);  

zval_string(foo, "bar"

, 1);  

zend_set_symbol( eg(active_symbol_table), "foo"

, foo);  

第一步、建立乙個zval結構,並設定型別。

第二步、賦值為bar。

第三步、將其加入當前作用域符號表,只有這樣使用者才能在php裡使用這個變數。

通過簡單的這三步,即可實現定義php變數。簡單的原因,在於核心為我們提供了強大的巨集。現在我們將巨集分別展開。

make_std_zval應用到的巨集有:

[cpp]view plain

copy

#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)展開後得到:

[cpp]view plain

copy

(foo) = (zval *) emalloc(

sizeof

(zval));  

(foo)->refcount__gc = 1;  

(foo)->is_ref__gc = 0;  

可以看出,make_std_zval做了三件事:分配記憶體、初始化zval結構中的refcount、is_ref。

zval_string應用到的巨集有:

[cpp]view plain

copy

#define zval_string(z, s, duplicate)   

#define z_strlen_p(zval_p)      z_strlen(*zval_p)

#define z_strlen(zval)          (zval).value.str.len

#define z_strval_p(zval_p)      z_strval(*zval_p)

#define z_strval(zval)          (zval).value.str.val

#define z_type_p(zval_p)            z_type(*zval_p)

#define z_type(zval)            (zval).type

#define is_string               6

展開後得到:

[cpp]view plain

copy

const

char

*__s=(

"foo"

);  

(foo).value.str.len=strlen(__s);  

(foo).value.str.val=(duplicate?estrndup(__s, (zval).value.str.len):(char

*)__s);  

(foo).type=6;  

zval_string做的工作是設定資料型別並賦值。

zend_set_symbol這裡只展開一部分巨集,因為它展開後過於複雜。

[cpp]view plain

copy

# define eg(v) (executor_globals.v)

展開部分後得到:

[cpp]view plain

copy

zend_set_symbol(executor_globals.active_symbol_table, 

"foo"

, foo);  

將變數名入當前作用域符號表。

注:之所以使用核心提供的巨集來分配記憶體、註冊變數作用域,是因為這樣能提高相容性。

原始碼研究 php變數

1 標量型別 布林型 bool,整型 int,浮點型 float,字串型 string 2 複雜型別 陣列 array,物件 object 3 特殊型別 null,資源 resource 這些變數都是怎麼實現的呢?我們都知道php是用 c 語言實現的,那是怎麼用c語言實現的呢?來看看php5.5.7...

php原始碼探索四 php擴充套件原始碼分析

1 最重要的entry 比如exif裡的 zend module entry exif module entry struct zend module entry 引數 描述 size,zend api,zend debug and zts 通常使用standard module header來填充...

Nginx原始碼分析之變數

server content by lua block map host var 2變數的定義方法有三種,var1是用set指令定義的 變數 1 是正則匹配出來的 變數var 2是用map指令定義的。http host並不是前面三種方法定義的變數,它是屬於 字首變數 它的字首是 http 表示從請求...