php內核分析之zval
學習PHP的同學對php內核方面的知識也許了解的還不是很清楚,那么下面小編就php內核之zval展開分析,希望對大家有用,更多內容請關注應屆畢業(yè)生網!
這里閱讀的php版本為PHP-7.1.0 RC3,閱讀代碼的平臺為linux
實際上,從這個函數(shù)開始,就已經進入到了zend引擎的范圍了。
zend_eval_string_ex(exec_direct, NULL, "Command line code", 1)
實際上是調用Zend/zend_execute_API.c
zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);
再進去是調用
result = zend_eval_stringl(str, str_len, retval_ptr, string_name);
這里的retval_ptr為NULL,string_name為"Command line code", str為"echo 12;"
zend_eval_stringl
其實這個函數(shù)主流程并不復雜。簡化下來就如下
ZEND_API int zend_eval_stringl(char *str, size_t str_len, zval *retval_ptr, char *string_name) /* {{{ */
{
...
new_op_array = zend_compile_string(&pv, string_name); /pic/p>
...
zend_execute(new_op_array, &local_retval); /pic/p>
...
retval = SUCCESS;
return retval;
}
先把php編譯為opcode,然后執(zhí)行這個opcode。只是這個函數(shù)有一些關鍵的'結構需要理一下。
zval
我們會看到
zval local_retval;
這樣的變量,然后會對這個變量進行如下操作:
ZVAL_UNDEF(&local_retval);
ZVAL_NULL(z)
ZVAL_FALSE(z)
ZVAL_TRUE(z)
ZVAL_BOOL(z, b)
ZVAL_LONG(z, l)
ZVAL_DOUBLE(z, d)
ZVAL_STR(z, s)
ZVAL_INTERNED_STR(z, s)
ZVAL_NEW_STR(z, s)
ZVAL_STR_COPY(z, s)
ZVAL_ARR(z, a)
ZVAL_NEW_ARR(z)
ZVAL_NEW_PERSISTENT_ARR(z)
ZVAL_OBJ(z, o)
ZVAL_RES(z, r)
ZVAL_NEW_RES(z, h, p, t)
ZVAL_NEW_PERSISTENT_RES(z, h, p, t)
ZVAL_REF(z, r)
ZVAL_NEW_EMPTY_REF(z)
ZVAL_NEW_REF(z, r)
ZVAL_NEW_PERSISTENT_REF(z, r)
ZVAL_NEW_AST(z, a)
ZVAL_INDIRECT(z, v)
ZVAL_PTR(z, p)
ZVAL_FUNC(z, f)
ZVAL_CE(z, c)
ZVAL_ERROR(z)
php是一個弱類型的語言,它可以用一個$var來代表string,int,array,object等。這個就是歸功于zval_struct結構
/pic/p>
struct _zval_struct {
zend_value value; /pic/p>
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /pic/IS_INT)
zend_uchar type_flags, /pic/p>
zend_uchar const_flags, /pic/p>
zend_uchar reserved) /pic/p>
} v;
uint32_t type_info; /pic/p>
} u1; /pic/p>
union {
uint32_t next; /pic/p>
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
uint32_t access_flags; /* class constant access flags */
uint32_t property_guard; /* single property guard */
} u2; /pic/p>
};
這個接口最重要的兩個字段是 value,存儲變量的值。另一個是u1.v.type 存儲變量的類型。這里,value也是一個結構
typedef union _zend_value {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str; /pic/p>
zend_array *arr; /pic/p>
zend_object *obj; /pic/p>
zend_resource *res; /pic/p>
zend_reference *ref; /pic/p>
zend_ast_ref *ast; /pic/p>
zval *zv;
void *ptr;
zend_class_entry *ce; /pic/p>
zend_function *func; /pic/p>
struct {
uint32_t w1;
uint32_t w2;
} ww;
} zend_value;
如果u1.v.type == IS_STRING, 那么value.str就是指向了zend_string結構。好了,php的'垃圾回收是通過引用計數(shù)來進行的,這個引用計數(shù)的計數(shù)器就放在zval.value.counted里面。
我們對zval設置的時候設置了一些宏來進行設置,比如:ZVAL_STRINGL是設置string,我們仔細看下調用堆棧:
ZVAL_STRINGL(&pv, str, str_len); /pic/p>
這個函數(shù)就是把pv設置為zend_string類型
/pic/p>
#define ZVAL_STRINGL(z, s, l) do { \
ZVAL_NEW_STR(z, zend_string_init(s, l, 0)); \
} while (0)
注意到,這里使用了一個寫法,do {} while(0) 來設置一個宏,這個是C里面比較好的寫法,這樣寫,能保證宏中定義的東西在for,if,等各種流程語句中不會出現(xiàn)語法錯誤。不過其實我們學習代碼的時候,可以忽略掉這個框框寫法。
zend_string_init(s, l, 0)
...
/pic/p>
static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, int persistent)
{
zend_string *ret = zend_string_alloc(len, persistent); /pic/p>
memcpy(ZSTR_VAL(ret), str, len);
ZSTR_VAL(ret)[len] = '\0';
return ret;
}
這個函數(shù)可以看的點有幾個:
persistent
這個參數(shù)是用來代表申請的空間是不是“臨時”的。這里說的臨時是zend提供的一種內存管理器,相關請求數(shù)據(jù)只服務于單個請求,最遲會在請求結束的時候釋放。
臨時內存申請對應的函數(shù)為:
void *emalloc(size_t size)
而永久內存申請對應的函數(shù)為:
malloc
zend_string_alloc
static zend_always_inline zend_string *zend_string_alloc(size_t len, int persistent)
{
zend_string *ret = (zend_string *)pemalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
GC_REFCOUNT(ret) = 1;
GC_TYPE_INFO(ret) = IS_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << 8);
zend_string_forget_hash_val(ret);
ZSTR_LEN(ret) = len;
return ret;
}
我們先看看zend_string的結構:
/pic/p>
struct _zend_string {
zend_refcounted_h gc; /pic/p>
zend_ulong h; /pic/p>
size_t len; /pic/p>
char val[1]; /pic/p>
};
_ZSTR_STRUCT_SIZE(len) gc+h+len的空間,最后給了val留了len+1的長度
#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
## GC_REFCOUNT(ret) = 1;
#define GC_REFCOUNT(p) (p)->gc.refcount
這里就看到一個結構zend_refcounted_h
typedef struct _zend_refcounted_h {
uint32_t refcount; /pic/p>
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type, /pic/p>
zend_uchar flags, /pic/p>
uint16_t gc_info) /pic/p>
} v;
uint32_t type_info; /pic/p>
} u; /pic/p>
} zend_refcounted_h;
回到我們的實例,我們調用的是
zend_string_init(s, l, 0) /pic/p>
返回的zend_string實際值為:
struct _zend_string {
struct {
uint32_t refcount; /pic/p>
union {
struct {
ZEND_ENDIAN_LOHI_3(
zend_uchar type, /pic/p>
zend_uchar flags,
uint16_t gc_info)
} v;
uint32_t type_info; /pic/p>
} u;
} gc;
zend_ulong h; /pic/p>
size_t len; /pic/p>
char val[1]; /pic/p>
};
結合到zval里面,那么ZVAL_STRINGL(&pv, str, str_len);返回的zval為
/pic/p>
struct _zval_struct {
union _zend_value {
zend_long lval;
double dval;
zend_refcounted *counted;
zend_string *str; /pic/p>
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type,
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved)
} v;
uint32_t type_info; /pic/p>
} u1;
union {
uint32_t next;
uint32_t cache_slot;
uint32_t lineno;
uint32_t num_args;
uint32_t fe_pos;
uint32_t fe_iter_idx;
uint32_t access_flags;
uint32_t property_guard;
} u2;
};
這里,就對zval結構有初步了解了。
另外建議記住幾個常用的類型,后續(xù)調試的時候會很有用
/* regular data types */
#define IS_UNDEF 0
#define IS_NULL 1
#define IS_FALSE 2
#define IS_TRUE 3
#define IS_LONG 4
#define IS_DOUBLE 5
#define IS_STRING 6
#define IS_ARRAY 7
#define IS_OBJECT 8
#define IS_RESOURCE 9
#define IS_REFERENCE 10
/* constant expressions */
#define IS_CONSTANT 11
#define IS_CONSTANT_AST 12
【php內核分析之zval】相關文章:
php內核分析之擴展01-31
php內核分析之opcode02-15
php內核分析之do-cli01-09
php內核分析之zend-compile10-17
php內核分析之全局變量12-14
php內核分析之sapi-module-struct10-04
php內核分析之ZTS和zend-try08-24
php學習之php配置03-11
php學習之php預定義變量11-02
- 相關推薦