在上一節中,分析了函數的定義,
函數的定義只是將函數名註冊到函數列表的過程.
下面繼續分析函數的參數.
如果沒有看就移步到>>原:PHP核心研究
函數的定義,
,
function $test($arg=11){
}
還是要看Lex的文法分析
[c]
unticked_function_declaration_statement:
function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
[/c]
parameter_list 就是分析參數的地方
經過分析找到瞭解析參數的函數
zend_do_receive_arg(ZEND_RECV, &tmp, &$$, NULL, &$1, &$2, 0 TSRMLS_CC);
這裡先要說一下 用來儲存函數的結構體zend_arg_info
[c]
typedef struct _zend_arg_info {
const char *name; //參數名
zend_uint name_len; //參數名長度
const char *class_name; //參數為類時,指定類名
zend_uint class_name_len;//類名長度
zend_bool array_type_hint;//參數是否是數組
zend_bool allow_null; //參數是否允許為空白
zend_bool pass_by_reference; //參數是否為引用 也就是有沒有使用&
zend_bool return_reference; //函數自身是否是一個引用函數
int required_num_args; //最少傳遞幾個參數
} zend_arg_info;
[/c]
zend_do_receive_arg定義在Zend/zend_compile.c中
[c]
void zend_do_receive_arg(zend_uchar op, const znode *var, const znode *offset, const znode *initialization, znode *class_type, const znode *varname, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
{
zend_op *opline;
zend_arg_info *cur_arg_info;//聲明一個函數結構指標
if (class_type->op_type == IS_CONST && //這裡是類相關處理 暫時跳過 講到類的時候再細說
跳過....
}
if (var->op_type == IS_CV &&
var->u.var == CG(active_op_array)->this_var &&
(CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) {
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
} else if (var->op_type == IS_VAR &&
CG(active_op_array)->scope &&
((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) &&
(Z_TYPE(varname->u.constant) == IS_STRING) &&
(Z_STRLEN(varname->u.constant) == sizeof("this")-1) &&
(memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this")) == 0)) {
zend_error(E_COMPILE_ERROR, "Cannot re-assign $this");
}
//建立一個op
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
CG(active_op_array)->num_args++;//參數的個數
opline->opcode = op; //中間碼 ZEND_RECV
opline->result = *var;//傳回值
opline->op1 = *offset;
if (op == ZEND_RECV_INIT) {
opline->op2 = *initialization;
} else {
CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
SET_UNUSED(opline->op2);
}
//複製參數列表到arr_info
CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
cur_arg_info->name_len = varname->u.constant.value.str.len;
cur_arg_info->array_type_hint = 0;
cur_arg_info->allow_null = 1;
cur_arg_info->pass_by_reference = pass_by_reference;
cur_arg_info->class_name = NULL;
cur_arg_info->class_name_len = 0;
//這個時候 cur_arg_info->name的值就是 $arg;也就是我們傳遞過來的參數名
if (class_type->op_type != IS_UNUSED) {//跳過
有略過....
}
opline->result.u.EA.type |= EXT_TYPE_UNUSED;
}
[/c]
如果函數有N個參數,那麼 此函數就會執行N次
下一節將繼續介紹 函數的傳回值
原文出處:原:PHP核心研究
函數的參數