在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...