亚洲国产日韩欧美在线a乱码,国产精品路线1路线2路线,亚洲视频一区,精品国产自,www狠狠,国产情侣激情在线视频免费看,亚洲成年网站在线观看

php內(nèi)核分析之zval

時(shí)間:2025-11-19 09:11:44 php語言 我要投稿

php內(nèi)核分析之zval

  學(xué)習(xí)PHP的同學(xué)對php內(nèi)核方面的知識也許了解的還不是很清楚,那么下面小編就php內(nèi)核之zval展開分析,希望對大家有用,更多內(nèi)容請關(guān)注應(yīng)屆畢業(yè)生網(wǎng)!

  這里閱讀的php版本為PHP-7.1.0 RC3,閱讀代碼的平臺為linux

  實(shí)際上,從這個(gè)函數(shù)開始,就已經(jīng)進(jìn)入到了zend引擎的范圍了。

  zend_eval_string_ex(exec_direct, NULL, "Command line code", 1)

  實(shí)際上是調(diào)用Zend/zend_execute_API.c

  zend_eval_stringl_ex(str, strlen(str), retval_ptr, string_name, handle_exceptions);

  再進(jìn)去是調(diào)用

  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í)這個(gè)函數(shù)主流程并不復(fù)雜。簡化下來就如下

  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í)行這個(gè)opcode。只是這個(gè)函數(shù)有一些關(guān)鍵的'結(jié)構(gòu)需要理一下。

  zval

  我們會(huì)看到

  zval local_retval;

  這樣的變量,然后會(huì)對這個(gè)變量進(jìn)行如下操作:

  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是一個(gè)弱類型的語言,它可以用一個(gè)$var來代表string,int,array,object等。這個(gè)就是歸功于zval_struct結(jié)構(gòu)

  /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>

  };

  這個(gè)接口最重要的兩個(gè)字段是 value,存儲變量的值。另一個(gè)是u1.v.type 存儲變量的類型。這里,value也是一個(gè)結(jié)構(gòu)

  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結(jié)構(gòu)。好了,php的'垃圾回收是通過引用計(jì)數(shù)來進(jìn)行的,這個(gè)引用計(jì)數(shù)的計(jì)數(shù)器就放在zval.value.counted里面。

  我們對zval設(shè)置的時(shí)候設(shè)置了一些宏來進(jìn)行設(shè)置,比如:ZVAL_STRINGL是設(shè)置string,我們仔細(xì)看下調(diào)用堆棧:

  ZVAL_STRINGL(&pv, str, str_len); /pic/p>

  這個(gè)函數(shù)就是把pv設(shè)置為zend_string類型

  /pic/p>

  #define ZVAL_STRINGL(z, s, l) do { \

  ZVAL_NEW_STR(z, zend_string_init(s, l, 0)); \

  } while (0)

  注意到,這里使用了一個(gè)寫法,do {} while(0) 來設(shè)置一個(gè)宏,這個(gè)是C里面比較好的寫法,這樣寫,能保證宏中定義的東西在for,if,等各種流程語句中不會(huì)出現(xiàn)語法錯(cuò)誤。不過其實(shí)我們學(xué)習(xí)代碼的時(shí)候,可以忽略掉這個(gè)框框?qū)懛ā?/p>

  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;

  }

  這個(gè)函數(shù)可以看的點(diǎn)有幾個(gè):

  persistent

  這個(gè)參數(shù)是用來代表申請的空間是不是“臨時(shí)”的。這里說的臨時(shí)是zend提供的一種內(nèi)存管理器,相關(guān)請求數(shù)據(jù)只服務(wù)于單個(gè)請求,最遲會(huì)在請求結(jié)束的時(shí)候釋放。

  臨時(shí)內(nèi)存申請對應(yīng)的函數(shù)為:

  void *emalloc(size_t size)

  而永久內(nèi)存申請對應(yīng)的函數(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的結(jié)構(gòu):

  /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

  這里就看到一個(gè)結(jié)構(gòu)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;

  回到我們的實(shí)例,我們調(diào)用的是

  zend_string_init(s, l, 0) /pic/p>

  返回的zend_string實(shí)際值為:

  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>

  };

  結(jié)合到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結(jié)構(gòu)有初步了解了。

  另外建議記住幾個(gè)常用的類型,后續(xù)調(diào)試的時(shí)候會(huì)很有用

  /* 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內(nèi)核分析之zval】相關(guān)文章:

php內(nèi)核分析之?dāng)U展01-31

php內(nèi)核分析之opcode02-15

php內(nèi)核分析之do-cli01-09

php內(nèi)核分析之zend-compile10-17

php內(nèi)核分析之全局變量12-14

php內(nèi)核分析之sapi-module-struct10-04

php內(nèi)核分析之ZTS和zend-try08-24

php學(xué)習(xí)之php配置03-11

php學(xué)習(xí)之php預(yù)定義變量11-02

  • 相關(guān)推薦