1.php代码先转化成抽象语法树,要执行还需要将抽象语法书转化操作指令集。
2.指令结构_zend_op
struct _zend_op {
const void *handler; //操作方式
znode_op op1; // 操作数1
znode_op op2; // 操作数2
znode_op result; //结果
uint32_t extended_value; // 额外存储
uint32_t lineno; // 行号
zend_uchar opcode; // 唯一对应一个handler
zend_uchar op1_type; // 类型
zend_uchar op2_type;
zend_uchar result_type;
};
// znode_op是个联合体
typedef union _znode_op {
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;
typedef struct _znode { /* used only during compilation */
zend_uchar op_type;
zend_uchar flag;
union {
znode_op op;
zval constant; /* replaced by literal/zv */
} u;
} znode;
3.inline 内联函数
函数不解析,不压栈,直接嵌入代码。
4.宏替换中的do{}while(0)
限定了宏内容的作用域,是为了保证宏替换的完整性,防止宏替换不全。
5.zend_copy 只拷贝value和u1,没有拷贝u2
#define ZVAL_COPY(z, v) \
do { \
zval *_z1 = (z); \
const zval *_z2 = (v); \
zend_refcounted *_gc = Z_COUNTED_P(_z2); \
uint32_t _t = Z_TYPE_INFO_P(_z2); \
ZVAL_COPY_VALUE_EX(_z1, _z2, _gc, _t); \
if ((_t & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0) { \
GC_REFCOUNT(_gc)++; \
} \
} while (0)
zend_string_copy 只是对refcount++
static zend_always_inline zend_string *zend_string_copy(zend_string *s)
{
if (!ZSTR_IS_INTERNED(s)) {
GC_REFCOUNT(s)++;
}
return s;
}
6.笔记地址
http://replay.xesv5.com/ll/2480/8e1b791bb452497dab0e2c39e4791038.flv.mp4