對zend中變數的一些說明

2021-07-10 13:20:06 字數 3806 閱讀 5566

在php中變數型別和值是通過c語言實現的,那php核心具體是怎麼實現的呢?

hashtable在php核心中廣泛被使用,而變數就是儲存在hashtable實現的符號表中.

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

核心中作用域的定義,php的所有 區域性變數,全域性變數,函式,類的 hash表 都在這裡定義了

struct _zend_executor_globals ;

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

<?php

$foo = 'bar';

?>

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

看一下變數$foo,在php核心中是怎麼實現的.

zval* foo;  

make_std_zval(foo);  //建立乙個zval結構,並設定型別。

zval_string(foo, "bar", 1); //賦值

zend_set_symbol( eg(active_symbol_table), "foo", foo); //將其加入當前作用域符號表,只有這樣使用者才能在php裡使用這個變數。

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

#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;   //是否被引用

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

zval_string用到的巨集:

#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

巨集展開後的**:

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使用到的一些巨集:

# define eg(v) (executor_globals.v)

展開後的**:

zend_set_symbol(executor_globals.active_symbol_table, "foo", foo);

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

下面我來看一下zval的定義:

zval在zend/zend.h中被定義,ypedef struct _zval_struct zval; //原來它是 _zval_struct 的別名

typedef union _zvalue_value str;

hashtable *ht; //陣列等

zend_object_value obj; //這是乙個物件

} zvalue_value;

struct _zval_struct ;

我們也可以通過寫php擴充套件的方式來展示一下:

php_function( test_test )

在這裡我們建立了乙個php的變數$a.

下面來講一下php弱型別變數的實現.

zend/zend_type.h

25 typedef unsigned char zend_bool;

26 typedef unsigned char zend_uchar;

27 typedef unsigned int zend_uint;

28 typedef unsigned long zend_ulong;

29 typedef unsigned short zend_ushort;

根據zval的結構,可以看到_zvalue_value是真正儲存資料的關鍵部分。通過共用體實現的弱型別變數宣告。

zend引擎是如何判別、儲存php中的多種資料型別的呢?

_zval_struct.type中儲存著乙個變數的真正型別,根據type來選擇如何獲取zvalue_value的值

type值列表(zend/zend.h):

#define is_null        0

#define is_long        1

#define is_double    2

#define is_bool        3

#define is_array    4

#define is_object    5

#define is_string    6

#define is_resource    7

#define is_constant    8

#define is_constant_array    9

來看乙個簡單的列子:

<?php

$a = 1;

//此時zval.type = is_long,那麼zval.value就去取lval.

$a = array();

//此時zval.type = is_array,那麼zval.value就去取ht.

這其中最複雜的,並且在開發第三方擴充套件中經常需要用到的是"資源型別".

在php中,任何不屬於php的內建的變數型別的變數,都會被看作資源來進行儲存。

比如:資料庫控制代碼、開啟的檔案控制代碼、開啟的socket控制代碼。

資源型別,需要使用ze提供的api函式來註冊,資源變數的宣告和使用將在單獨的篇目中進行詳細介紹。

正是因為ze這樣的處理方式,使php就實現了弱型別,而對於ze的來說,它所面對的永遠都是同一種型別zval。

PHP中對變數的一些說明

如果程式比較大,引用同乙個物件的變數比較多,並且希望用完該物件後手工清除它,個人建議用 方式,然後用 var null的方式清除.php5中對於大陣列的傳遞,建議用 方式,畢竟節省記憶體空間使用。php中對於位址的指向功能不是由使用者自己來實現的,是由zend核心實現的 php中引用採用的是 寫時拷...

ALV的一些說明

abap alv alv是系統的一種網格的顯示方式,這種方式帶有彙總 排序 篩選等功能,alv格式的資料是以單元格為單位顯示,不象一般的寫屏方式拷出來或是匯出成檔案不同列的內容粘在一塊,這種方式便於資料匯出來放在電子 裡進行加工.slis fieldcat alv中的部分欄位及意義 fieldnam...

string npos的一些說明

string npos的一些說明 static const size t npos 1 表示 size t 的最大值 maximum value for size t 如果對 1表示size t的最大值有疑問可以採用如下 驗證 include include include using namesp...