opcode 運算元 5 中不同的型別

coder_study發表於2019-11-06

zend_op_array.opcodes指向指令列表,具體每條指令的結構如下:

struct _zend_op {  //  *opline  *opcodes
    const void *handler; //指令執行handler
    znode_op op1; //運算元1
    znode_op op2; //運算元型別實際就是個32位整形,它主要用於儲存一些變數的索引位置、數值記錄等等
    znode_op result; //返回值
    uint32_t extended_value;
    uint32_t lineno;
    zend_uchar opcode; //opcode指令
    zend_uchar op1_type; //運算元1型別
    zend_uchar op2_type;
    zend_uchar result_type; //返回值型別
};

//運算元結構
//比如賦值語句:"$a = 45;",兩個運算元分別記錄"$a"、"45"的儲存位置,執行時根據op2取到值"45",
//然後賦值給"$a",而"$a"的位置透過op1獲取到
//當然運算元並不是全部這麼用的,上面只是賦值時候的情況,其它操作會有不同的用法
//如函式呼叫時的傳參,op1記錄的就是傳遞的引數是第幾個,op2記錄的是引數的儲存位置,
//result記錄的是函式接收引數的儲存位置。
typedef union _znode_op { //運算元型別實際就是個32位整形,它主要用於儲存一些變數的索引位置、數值記錄等等
    uint32_t      constant; //運算元記錄著當前指令的關鍵資訊, 可以用於變數的儲存、訪問
    uint32_t      var;
    uint32_t      num;
    uint32_t      opline_num; /*  Needs to be signed */
#if ZEND_USE_ABS_JMP_ADDR
    zend_op       *jmp_addr;
#else
    uint32_t      jmp_offset;
#endif
#if ZEND_USE_ABS_CONST_ADDR
    zval          *zv;
#endif
} znode_op;
   //運算元有5種不同的型別;
#define IS_CONST    (1<<0)  //字面量,編譯時就可確定且不會改變的值,比如:$a = "hello~",其中字串"hello~"就是常量
#define IS_TMP_VAR  (1<<1) //臨時變數 $a = "hello~" . time(),其中"hello~" . time()的值型別就是IS_TMP_VAR
                            //"123" + $b的結果型別也是IS_TMP_VAR,從這兩個例子可以猜測,臨時變數多是執行期間其它
   //型別組合現生成的一箇中間值,由於它是現生成的,所以把IS_TMP_VAR賦值給IS_CV變數時不會增加其引用計數
#define IS_VAR      (1<<2)//PHP變數
                          //這個很容易認為是PHP指令碼里的變數,其實不是,這裡PHP變數的含義可以這樣理解:PHP變數是沒有顯
                          //式的在PHP指令碼中定義的,不是直接在程式碼透過$var_name定義的
   //。這個型別最常見的例子是PHP函式的返回值,再如$a[0]陣列這種,它取出的值也是IS_VAR,再比如$$a這種
#define IS_UNUSED   (1<<3)  /* Unused variable */   //表示運算元沒有用
#define IS_CV       (1<<4)  /* Compiled variable */
   //PHP指令碼變數,即指令碼里透過$var_name定義的變數,這些變數是編譯階段確定的,所以是compile variable

   //result_type除了上面幾種型別外還有一種型別EXT_TYPE_UNUSED (1<<5),返回值沒有使用時會用到,
   //這個跟IS_UNUSED的區別是:IS_UNUSED表示本操作返回值沒有意義(也可簡單的認為沒有返回值),
   //而EXT_TYPE_UNUSED的含義是有返回值,但是沒有用到,比如函式返回值沒有接收
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章