/* {{{ get_var_name * * 這個擴充要求PHP >= 5.1 * 因為依賴PHP 5.1引入的compiled variable * * 在PHP空間匯出一個get_var_name函數. * echo get_var_name($var_name); // expect: var_name * echo get_var_name($lineno=100); // expect: lineno */ PHP_FUNCTION(get_var_name) { int len; char *strg = ""; if(ZEND_NUM_ARGS() < 1) { return; } /* 顯示所有的編譯變數 int i; zend_compiled_variable *vars = EG(active_op_array)->vars; for(i=0; i < EG(active_op_array)->last_var; ++i) { // last_var 最後一個編譯變數的索引 spprintf(&strg, 0, "%s\\nVar:%s\\n", strg, EG(active_op_array)->vars[i].name); ++vars; } */ zend_op *pre_opline_ptr = *EG(opline_ptr); pre_opline_ptr--; // 支援這類的調用: get_var_name($a="VALUE"); // expect: a // 這裡增加在賦值的情況下也能正確返回變數的名字的處理方法, 如果方法參數是賦值的的話, 編譯的OPCODE 中SEND_VAR之前將會 // 有一個ZEND_ASSIGN 操作, 並且ZEND_ASSIGN操作的傳回值被使用.比如: $c = $d + 1; $d + 1的傳回值就被使用了. 就可以確認 // 是前面的調用方式 zend_op *pre_pre_online_ptr = pre_opline_ptr - 1; if(pre_pre_online_ptr && pre_pre_online_ptr->opcode == ZEND_ASSIGN && !(pre_pre_online_ptr->result.u.EA.type & EXT_TYPE_UNUSED)) { // 通過賦值之前的zend_op來擷取變數資訊 pre_opline_ptr = pre_pre_online_ptr; } int index; // 比如get_var_name($name); 這時SEND_VAR OPCODE的op1運算元類型就是IS_CV 也就是IS Compiled Variable // 只有compiled variable才是直接儲存索引的. PHP >= 5.1 if(pre_opline_ptr->op1.op_type == IS_CV) { index = pre_opline_ptr->op1.u.var; } else { // 請參考VLD的原始碼 $VLD_SRC/srm_oparray.c LINE:320 vld_dump_znode函數 index = pre_opline_ptr->op1.u.var / sizeof(temp_variable); } zend_compiled_variable var = EG(active_op_array)->vars[index]; len = spprintf(&strg, 0, "%s", strg, var.name); RETURN_STRINGL(strg, len, 0); } /* }}} */ |