opcode
___________________________________________________________________________________________________
opcode是計(jì)算機(jī)指令中的一部分,用于指定要執(zhí)行的操作争拐,指令的格式和規(guī)范由處理器的指令規(guī)范指定院仿。除了指令本身以外通常還有指令所需要的操作數(shù),可能有的指令不需要顯式的操作數(shù)莱坎,這些操作數(shù)可能是寄存器中的值,堆棧中的值眼滤,某塊內(nèi)存的值或者IO端口中的值等等寺渗。
通常opcode還有另一種稱謂:字節(jié)碼(byte codes).例如,.NET的通用中間語言等等
PHP的opcode
____________________________________________________________________________________________________
PHP中的opcode則屬于前面介紹中的后者,PHP是構(gòu)建在Zend虛擬機(jī)(Zend VM)之上的疼进。PHP的opcode就是Zend虛擬機(jī)中的指令薪缆。
在PHP實(shí)現(xiàn)內(nèi)部,opcode由如下的結(jié)構(gòu)體表示:
struct _zend_op {
opcode_handler_t handler;//執(zhí)行該opcode時(shí)調(diào)用的處理函數(shù)
znode result;
znode op1;
znode op2;
ulong extended_value;
uint lineno;
zend_uchar opcode;//opcode代碼
}
和CPU的指令類似伞广,有一個(gè)標(biāo)示指令的opcode字段拣帽,以及這個(gè)opcode所操作的操作數(shù),PHP不像匯編那么底層嚼锄,在腳本實(shí)際執(zhí)行的時(shí)候可能還需要其它更多的信息减拭,extended_value字段就保存了這類信息,其中的result域是保存該指令執(zhí)行完成后的結(jié)果区丑。
例如下代碼是在編譯器遇到print語句的時(shí)候進(jìn)行編譯的函數(shù):
void zend_do_print(znode *result, const znode *arg TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->result.op_type = IS_TMP_VAR;
opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->opcode = ZEND_PRINT;
opline->op1 = *arg;
SET_UNUSED(opline->op2);
*result = opline->result;
}
這個(gè)函數(shù)創(chuàng)建一條zend_op,將返回值的類型設(shè)置為臨時(shí)變量(IS_TMP_VAR),并為臨時(shí)變量申請(qǐng)空間拧粪,隨后指定opcode為ZEND_PRINT,并將傳遞進(jìn)來的參數(shù)賦值給這條opcode的第一個(gè)操作數(shù)。這樣在最終執(zhí)行這條opcode的時(shí)候沧侥,Zend引擎能獲取到足夠的信息以邊輸出內(nèi)容可霎。
下面這個(gè)函數(shù)是編譯器在遇到echo 語句的時(shí)候進(jìn)行編譯的函數(shù):
void zend_do_echo(const znode *arg TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_ECHO;
opline->op1 = *arg;
SET_UNUSED(opline->op2);
}
可以看到echo處理除了指定opcode以外,還將echo的參數(shù)傳遞給op1,這里并沒有設(shè)置opcode的result結(jié)果字段宴杀。從這里我們也能看出print和echo的區(qū)別來癣朗,print有返回值,而echo沒有旺罢,這個(gè)的沒有和返回null是不同的斯棒,如果嘗試將echo 的值賦值給某個(gè)變量或者傳遞給函數(shù)都會(huì)出現(xiàn)語法錯(cuò)誤。
PHP腳本編譯為opcode保存在op_array中主经,其內(nèi)部存儲(chǔ)的結(jié)構(gòu)如下:
struct _zend_op_array{
zend_uchar type;
char *function_name
....
}
執(zhí)行的時(shí)候由下面的execute函數(shù)執(zhí)行
ZEND_API void execute(zend_op_array *op_array TSRMLS_DC){
}
php初學(xué)者---千鋒php課堂筆記