php unset变量
<?php $a="abc"; $b="def"; unset($a,$b); echo $a."\n"; echo $b."\n";
1)词法分析
<ST_IN_SCRIPTING>"unset" { return T_UNSET; }
2)语法分析
unticked_statement:
| T_UNSET '(' unset_variables ')' ';' //unset($a,$b) 还能这么用呢,第一次知道
unset_variables:
unset_variable
| unset_variables ',' unset_variable
;
unset_variable:
variable { zend_do_end_variable_parse(&$1, BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1 TSRMLS_CC); }
;
3)生成opcode
void zend_do_unset(const znode *variable TSRMLS_DC) /* {{{ */ { zend_op *last_op; zend_check_writable_variable(variable); if (variable->op_type == IS_CV) { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_UNSET_VAR; SET_NODE(opline->op1, variable); SET_UNUSED(opline->op2); SET_UNUSED(opline->result); opline->extended_value = ZEND_FETCH_LOCAL | ZEND_QUICK_SET; } else { //不是IS_CV类型的处理 } }
4)执行opcode
static int ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval tmp, *varname; HashTable *target_symbol_table; SAVE_OPLINE(); if (IS_CV == IS_CV && IS_UNUSED == IS_UNUSED && (opline->extended_value & ZEND_QUICK_SET)) { if (EG(active_symbol_table)) { zend_compiled_variable *cv = &CV_DEF_OF(opline->op1.var); zend_delete_variable(EX(prev_execute_data), EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value TSRMLS_CC); //从active_symbol_table中清除cv->name以及相应值,再从CV数组中清除此值 EX_CV(opline->op1.var) = NULL; } else if (EX_CV(opline->op1.var)) { zval_ptr_dtor(EX_CV(opline->op1.var)); EX_CV(opline->op1.var) = NULL; } CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } //不会被执行了 }
#define CV_DEF_OF(i) (EG(active_op_array)->vars[i])
#undef EX_CV
#define EX_CV(var) EX(CVs)[var]
#undef EX_CVs
#define EX_CVs() EX(CVs)
#undef EX_T
#define EX_T(offset) (*(temp_variable *)((char *) EX(Ts) + offset))
#undef EX_Ts
#define EX_Ts() EX(Ts)
ZEND_API void zend_delete_variable(zend_execute_data *ex, HashTable *ht, const char *name, int name_len, ulong hash_value TSRMLS_DC) /* {{{ */
{
if (zend_hash_quick_del(ht, name, name_len, hash_value) == SUCCESS) {
name_len--;
while (ex && ex->symbol_table == ht) {
int i;
if (ex->op_array) {
for (i = 0; i < ex->op_array->last_var; i++) {
if (ex->op_array->vars[i].hash_value == hash_value &&
ex->op_array->vars[i].name_len == name_len &&
!memcmp(ex->op_array->vars[i].name, name, name_len)) {
ex->CVs[i] = NULL;
break;
}
}
}
ex = ex->prev_execute_data;
}
}
}
ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag)
{
uint nIndex;
Bucket *p;
#ifdef ZEND_SIGNALS
TSRMLS_FETCH();
#endif
IS_CONSISTENT(ht);
if (flag == HASH_DEL_KEY) {
h = zend_inline_hash_func(arKey, nKeyLength);
}
nIndex = h & ht->nTableMask;
p = ht->arBuckets[nIndex];
while (p != NULL) {
if ((p->h == h)
&& (p->nKeyLength == nKeyLength)
&& ((p->nKeyLength == 0) /* Numeric index (short circuits the memcmp() check) */
|| !memcmp(p->arKey, arKey, nKeyLength))) { /* String index */
HANDLE_BLOCK_INTERRUPTIONS();
if (p == ht->arBuckets[nIndex]) {
ht->arBuckets[nIndex] = p->pNext;
} else {
p->pLast->pNext = p->pNext;
}
if (p->pNext) k{
p->pNext->pLast = p->pLast;
}
if (p->pListLast != NULL) {
p->pListLast->pListNext = p->pListNext;
} else {
/* Deleting the head of the list */
ht->pListHead = p->pListNext;
}
if (p->pListNext != NULL) {
p->pListNext->pListLast = p->pListLast;
} else {
ht->pListTail = p->pListLast;
}
if (ht->pInternalPointer == p) {
ht->pInternalPointer = p->pListNext;
}
if (ht->pDestructor) {
ht->pDestructor(p->pData);
}
if (p->pData != &p->pDataPtr) {
pefree(p->pData, ht->persistent);
}
pefree(p, ht->persistent);
HANDLE_UNBLOCK_INTERRUPTIONS();
ht->nNumOfElements--;
return SUCCESS;
}
p = p->pNext;
}
return FAILURE;
}