1. <?php
  2. function test()
  3. {
  4. echo "abc";
  5. }
  6.  
  7. test();
  8. ?>

结论:

一 编译

a.对 函数声明进行词法分析和语法分析:在语法分析中的函数zend_do_begin_function_declaration 作用是: 初始化zend_op_array,填充 function_name ,line_start ,设定相应opcode:ZEND_DECLARE_FUNCTION, 以key为function_name, value为 zend_op_array,存入CG(function_table)中;zend_do_end_function_declaration作用为: 填充zend_op_array中的line_end

b.对 函数调用进行词法分析和语法分析: 语法分析中的函数 zend_do_begin_function_call 作用是:将函数名转化为小写,zend_do_end_function_call中设定opcode:ZEND_DO_FCALL, op1为function_name,op2为no use

二 执行

c.执行a中的hanlder ZEND_DECLARE_FUNCTION,如果函数名重复出现,则报错

d.执行b中的handler ZEND_DO_FCALL ,

1)词法分析,提取function 关键字

  1. <ST_IN_SCRIPTING>"function" {
  2. return T_FUNCTION;
  3. }

2)语法分析,每一个字符串表达式后面跟着一个方法,此方法是用来生成opcode

  1. function:
  2.   T_FUNCTION { $$.u.op.opline_num = CG(zend_lineno); }
  3. ;
  4.  
  5. unticked_function_declaration_statement:
  6.   function is_reference T_STRING { zend_do_begin_function_declaration(&$, &$, , $.op_type, NULL TSRMLS_CC); }
  7. '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$ TSRMLS_CC); }
  8. ;
  9.  
  10. parameter_list:
  11.   non_empty_parameter_list
  12. | /* empty */
  13. ;

  14. //用来处理参数
  15. non_empty_parameter_list:
  16. optional_class_type T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=; zend_do_receive_arg(ZEND_RECV, &$, &$$, NULL, &$, TSRMLS_CC); } //$$.u.op.num=1 说明是第一个参数,也只存在一个参数
  17. | optional_class_type '&' T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=; zend_do_receive_arg(ZEND_RECV, &$, &$$, NULL, &$, TSRMLS_CC); } //这种方法已经取消了,估计是向下兼容
  18. | optional_class_type '&' T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=; zend_do_receive_arg(ZEND_RECV_INIT, &$, &$$, &$, &$, TSRMLS_CC); }
  19. | optional_class_type T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=; zend_do_receive_arg(ZEND_RECV_INIT, &$, &$$, &$, &$, TSRMLS_CC); }
  20. | non_empty_parameter_list ',' optional_class_type T_VARIABLE { $$=$; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$, &$$, NULL, &$, TSRMLS_CC); } // $$.u.op.num++递增,多个参数,用逗号分隔
  21. | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { $$=$; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$, &$$, NULL, &$, TSRMLS_CC); }
  22. | non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { $$=$; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$, &$$, &$, &$, TSRMLS_CC); }
  23. | non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { $$=$; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$, &$$, &$, &$, TSRMLS_CC); }
  24. ;

对函数头进行语法分析 ,主要 往zend_op_array中填充信息,比如 函数开始行号

  1. void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
  2. {
  3. zend_op_array op_array;
  4. char *name = function_name->u.constant.value.str.val;
  5. int name_len = function_name->u.constant.value.str.len;
  6. int function_begin_line = function_token->u.op.opline_num;
  7. zend_uint fn_flags;
  8. const char *lcname;
  9. zend_bool orig_interactive;
  10. ALLOCA_FLAG(use_heap)
  11.  
  12. if (is_method) {
  13. //忽略,这是针对类方法的
  1. fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
  2. } else {
  3. fn_flags = ;
  4. }
  5. if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
  6. zend_error(E_STRICT, "Static function %s%s%s() should not be abstract", is_method ? CG(active_class_entry)->name : "", is_method ? "::" : "", Z_STRVAL(function_name->u.constant));
  7. }
  8.  
  9. function_token->u.op_array = CG(active_op_array);//保存之前的CG(active_op_array),zend_do_end_funciton_declaration函数里将恢复CG(active_op_array)
  10.  
  11. orig_interactive = CG(interactive);
  12. CG(interactive) = ;
  13. init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
  14. CG(interactive) = orig_interactive;
  1. op_array.function_name = name; //填充functio_name字段
  1. if (return_reference) {
  2. op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
  3. }
  4. op_array.fn_flags |= fn_flags;
  5.  
  6. op_array.scope = is_method?CG(active_class_entry):NULL;
  7. op_array.prototype = NULL;
  1. op_array.line_start = zend_get_compiled_lineno(TSRMLS_C); //填充 函数首行行号
  2. if (is_method) {
  3. //忽略,这是针对类方法的处理
  1. } else {
  2. zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
  3. zval key;
  4.  
  5. if (CG(current_namespace)) { //针对命名空间的
  6. /* Prefix function name with current namespace name */
  7. znode tmp;
  8.  
  9. tmp.u.constant = *CG(current_namespace);
  10. zval_copy_ctor(&tmp.u.constant);
  11. zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
  12. op_array.function_name = Z_STRVAL(tmp.u.constant);
  13. name_len = Z_STRLEN(tmp.u.constant);
  14. lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
  15. } else {
  1. lcname = zend_str_tolower_dup(name, name_len); //函数名设置为小写
  2. }
  3. opline->opcode = ZEND_DECLARE_FUNCTION; //设置执行时的handler,在这里,如果函数名重复出现,会提示 已声明过函数
  4. opline->op1_type = IS_CONST;
  5. build_runtime_defined_function_key(&key, lcname, name_len TSRMLS_CC);
  6. opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC); //将key存入到zend_op_array中的literals中,他本身是个数组,即op1.constant是键,值是key
  7. Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
  8. opline->op2_type = IS_CONST;
  9. LITERAL_STRINGL(opline->op2, lcname, name_len, ); //opline->op2.constant设置为 literals数组中的键,值为lcname
  10. CALCULATE_LITERAL_HASH(opline->op2.constant);
  11. opline->extended_value = ZEND_DECLARE_FUNCTION;
  1.  
  1. //放入CG中函数符号表,上面的key为 \0函数名文件名称,不知道为什么这样写?为什么不把函数名 直接存入 函数符号表?
  2. zend_hash_quick_update(CG(function_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
  3. zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context)));
  4. zend_init_compiler_context(TSRMLS_C);
  5. }
  6.  
  7. //忽略
  1. }
  2. }
  1. ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length) /* {{{ */
  2. {
  3. register unsigned char *str = (unsigned char*)source;
  4. register unsigned char *result = (unsigned char*)dest;
  5. register unsigned char *end = str + length;
  6.  
  7. while (str < end) {
  8. *result++ = zend_tolower((int)*str++);
  9. }
  10. *result = '\0';
  11.  
  12. return dest;
  13. }
  14. /* }}} */
  15.  
  16. ZEND_API char *zend_str_tolower_dup(const char *source, unsigned int length) /* {{{ */
  17. {
  18. return zend_str_tolower_copy((char *)emalloc(length+), source, length);
  19. }
  1. static void build_runtime_defined_function_key(zval *result, const char *name, int name_length TSRMLS_DC) /* {{{ */
  2. {
  3. char char_pos_buf[];
  4. uint char_pos_len;
  5. const char *filename;
  6.  
  7. char_pos_len = zend_sprintf(char_pos_buf, "%p", LANG_SCNG(yy_text));
  8. if (CG(active_op_array)->filename) {
  9. filename = CG(active_op_array)->filename;
  10. } else {
  11. filename = "-";
  12. }
  13.  
  14. /* NULL, name length, filename length, last accepting char position length */
  15. result->value.str.len = +name_length+strlen(filename)+char_pos_len;
  16.  
  17. /* must be binary safe */
  18. result->value.str.val = (char *) safe_emalloc(result->value.str.len, , );
  19. result->value.str.val[] = '\0';
  20. sprintf(result->value.str.val+, "%s%s%s", name, filename, char_pos_buf);
  21.  
  22. result->type = IS_STRING;
  23. Z_SET_REFCOUNT_P(result, );
  24. }
  1. static inline void zend_insert_literal(zend_op_array *op_array, const zval *zv, int literal_position TSRMLS_DC) /* {{{ */
  2. {
  3. if (Z_TYPE_P(zv) == IS_STRING || Z_TYPE_P(zv) == IS_CONSTANT) {
  4. zval *z = (zval*)zv;
  5. Z_STRVAL_P(z) = (char*)zend_new_interned_string(Z_STRVAL_P(zv), Z_STRLEN_P(zv) + , TSRMLS_CC);
  6. }
  7. CONSTANT_EX(op_array, literal_position) = *zv;
  8. Z_SET_REFCOUNT(CONSTANT_EX(op_array, literal_position), );
  9. Z_SET_ISREF(CONSTANT_EX(op_array, literal_position));
  10. op_array->literals[literal_position].hash_value = ;
  11. op_array->literals[literal_position].cache_slot = -;
  12. }
  13. /* }}} */
  14.  
  15. /* Is used while compiling a function, using the context to keep track
  16. of an approximate size to avoid to relocate to often.
  17. Literals are truncated to actual size in the second compiler pass (pass_two()). */
  18. int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC) /* {{{ */
  19. {
  20. int i = op_array->last_literal;
  21. op_array->last_literal++;
  22. if (i >= CG(context).literals_size) {
  23. while (i >= CG(context).literals_size) {
  24. CG(context).literals_size += ; /* FIXME */
  25. }
  26. op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));
  27. }
  28. zend_insert_literal(op_array, zv, i TSRMLS_CC);
  29. return i;
  30. }
  1. zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
  2. {
  3. zend_uint next_op_num = op_array->last++;
  4. zend_op *next_op;
  5.  
  6. if (next_op_num >= CG(context).opcodes_size) {
  7. if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
  8. /* we messed up */
  9. zend_printf("Ran out of opcode space!\n"
  10. "You should probably consider writing this huge script into a file!\n");
  11. zend_bailout();
  12. }
  13. CG(context).opcodes_size *= ;
  14. op_array_alloc_ops(op_array, CG(context).opcodes_size);
  15. }
  16.  
  17. next_op = &(op_array->opcodes[next_op_num]);
  18.  
  19. init_op(next_op TSRMLS_CC);
  20.  
  21. return next_op;
  22. }

对函数体进行语法分析,主要是往zend_op_array中填充 函数结束行号,使用 pass_two函数,遍历CG(active_op_array)中的opcodes,设置zend_op 的handler

  1. void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /* {{{ */
  2. {
  3. char lcname[];
  4. int name_len;
  5.  
  6. zend_do_extended_info(TSRMLS_C);
  7. zend_do_return(NULL, TSRMLS_CC);
  8.  
  9. pass_two(CG(active_op_array) TSRMLS_CC);
  10. zend_release_labels(TSRMLS_C);
  11.  
  12. if (CG(active_class_entry)) {
  13. zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
  14. } else {
  15. /* we don't care if the function name is longer, in fact lowercasing only
  16. * the beginning of the name speeds up the check process */
  17. name_len = strlen(CG(active_op_array)->function_name);
  18. zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-));
  19. lcname[sizeof(lcname)-] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
  20. if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != ) {
  21. zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME);
  22. }
  23. }
  1. //得到函数体结束的 行
  2. CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
  3. CG(active_op_array) = function_token->u.op_array;
  4.  
  5. /* Pop the switch and foreach seperators */
  6. zend_stack_del_top(&CG(switch_cond_stack));
  7. zend_stack_del_top(&CG(foreach_copy_stack));
  8. }
  1. ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
  2. {
  3. zend_op *opline, *end;
  4.  
  5. if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
  6. return ;
  7. }
  8. if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
  9. zend_update_extended_info(op_array TSRMLS_CC);
  10. }
  11. if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
  12. zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
  13. }
  14.  
  15. if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) {
  16. op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var);
  17. CG(context).vars_size = op_array->last_var;
  18. }
  19. if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) {
  20. op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
  21. CG(context).opcodes_size = op_array->last;
  22. }
  23. if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) {
  24. op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
  25. CG(context).literals_size = op_array->last_literal;
  26. }
  27.  
  28. opline = op_array->opcodes;
  29. end = opline + op_array->last;
  30. while (opline < end) {
  31. if (opline->op1_type == IS_CONST) {
  32. opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
  33. }
  34. if (opline->op2_type == IS_CONST) {
  35. opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
  36. }
  37. switch (opline->opcode) {
  38. case ZEND_GOTO:
  39. if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
  40. zend_resolve_goto_label(op_array, opline, TSRMLS_CC);
  41. }
  42. /* break omitted intentionally */
  43. case ZEND_JMP:
  44. opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
  45. break;
  46. case ZEND_JMPZ:
  47. case ZEND_JMPNZ:
  48. case ZEND_JMPZ_EX:
  49. case ZEND_JMPNZ_EX:
  50. case ZEND_JMP_SET:
  51. case ZEND_JMP_SET_VAR:
  52. opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
  53. break;
  54. }
  55. ZEND_VM_SET_OPCODE_HANDLER(opline);
  56. opline++;
  57. }
  58.  
  59. op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
  60. return ;
  61. }
  1. ZEND_API void zend_vm_set_opcode_handler(zend_op* op)
  2. {
  3. op->handler = zend_vm_get_opcode_handler(zend_user_opcodes[op->opcode], op);
  4. }
  5.  
  6. static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op)
  7. {
  8. static const int zend_vm_decode[] = {
  9. _UNUSED_CODE, /* 0 */
  10. _CONST_CODE, /* 1 = IS_CONST */
  11. _TMP_CODE, /* 2 = IS_TMP_VAR */
  12. _UNUSED_CODE, /* 3 */
  13. _VAR_CODE, /* 4 = IS_VAR */
  14. _UNUSED_CODE, /* 5 */
  15. _UNUSED_CODE, /* 6 */
  16. _UNUSED_CODE, /* 7 */
  17. _UNUSED_CODE, /* 8 = IS_UNUSED */
  18. _UNUSED_CODE, /* 9 */
  19. _UNUSED_CODE, /* 10 */
  20. _UNUSED_CODE, /* 11 */
  21. _UNUSED_CODE, /* 12 */
  22. _UNUSED_CODE, /* 13 */
  23. _UNUSED_CODE, /* 14 */
  24. _UNUSED_CODE, /* 15 */
  25. _CV_CODE /* 16 = IS_CV */
  26. };
  27. return zend_opcode_handlers[opcode * + zend_vm_decode[op->op1_type] * + zend_vm_decode[op->op2_type]]; //通过 zend_op中的opcode 和左右值类型 ,计算出实际的handler;zend_opcode_handlers是一个巨大的数组,里面都是指针函数
  28. }

如果函数体中,还有其他数据,例如赋值,就把相应opcode放到zend_op_array中的opcodes中

  1. static int ZEND_FASTCALL ZEND_DECLARE_FUNCTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  2. {
  3. USE_OPLINE
  4.  
  5. SAVE_OPLINE();
  6. do_bind_function(EX(op_array), opline, EG(function_table), );
  7. CHECK_EXCEPTION();
  8. ZEND_VM_NEXT_OPCODE();
  9. }

//在执行期间,将函数名放入 EG(function_table)中,如果发现已经有了,则报错

  1. ZEND_API int do_bind_function(const zend_op_array *op_array, zend_op *opline, HashTable *function_table, zend_bool compile_time) /* {{{ */
  2. {
  3. zend_function *function;
  4. zval *op1, *op2;
  5.  
  6. if (compile_time) {
  7. op1 = &CONSTANT_EX(op_array, opline->op1.constant);
  8. op2 = &CONSTANT_EX(op_array, opline->op2.constant);
  9. } else {
  10. op1 = opline->op1.zv; //这里的op1.zv的值是通过上面的pass_two这个函数中得到的,他会遍历zend_op_array中的opcodes,如果op1_type为 IS_CONST,就会进行把zend_op_array中的literals相应的值赋给op1.zv
  11. op2 = opline->op2.zv; //同上
  12. }

  13. //这里的op1为上面的\0函数名文件名称,从EG(function_table)中取出,值赋给function
  14. zend_hash_quick_find(function_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void *) &function);
    //将键为op2(只有函数名),值为function,插入到EG(function)中,如果插入失败,说明函数多次被插入,要报函数已被声明的提示
  15. if (zend_hash_quick_add(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+, Z_HASH_P(op2), function, sizeof(zend_function), NULL)==FAILURE) {
  16. int error_level = compile_time ? E_COMPILE_ERROR : E_ERROR;
  17. zend_function *old_function;
  18.  
  19. if (zend_hash_quick_find(function_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+, Z_HASH_P(op2), (void *) &old_function)==SUCCESS
  20. && old_function->type == ZEND_USER_FUNCTION
  21. && old_function->op_array.last > ) {
  22. zend_error(error_level, "Cannot redeclare %s() (previously declared in %s:%d)",
  23. function->common.function_name,
  24. old_function->op_array.filename,
  25. old_function->op_array.opcodes[].lineno);
  26. } else {
  27. zend_error(error_level, "Cannot redeclare %s()", function->common.function_name);
  28. }
  29. return FAILURE;
  30. } else {
  31. (*function->op_array.refcount)++;
  32. function->op_array.static_variables = NULL; /* NULL out the unbound function */
  33. return SUCCESS;
  34. }
  35. }

对于 调用函数时的编译

  1. function_call:
  2. namespace_name '(' { $.u.op.opline_num = zend_do_begin_function_call(&$, TSRMLS_CC); }
  3. function_call_parameter_list
  4. ')' { zend_do_end_function_call(&$, &$$, &$, , $.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
  5. | T_NAMESPACE T_NS_SEPARATOR namespace_name '(' { $.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$.u.constant); zend_do_build_namespace_name(&$, &$, &$ TSRMLS_CC); $.u.op.opline_num = zend_do_begin_function_call(&$, TSRMLS_CC); }
  6. function_call_parameter_list
  7. ')' { zend_do_end_function_call(&$, &$$, &$, , $.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
  8. | T_NS_SEPARATOR namespace_name '(' { $.u.op.opline_num = zend_do_begin_function_call(&$, TSRMLS_CC); }
  9. function_call_parameter_list
  10. ')' { zend_do_end_function_call(&$, &$$, &$, , $.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); }
  11. | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { $.u.op.opline_num = zend_do_begin_class_member_function_call(&$, &$ TSRMLS_CC); }
  12. function_call_parameter_list
  13. ')' { zend_do_end_function_call($.u.op.opline_num?NULL:&$, &$$, &$, $.u.op.opline_num, $.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
  14. | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$, BP_VAR_R, TSRMLS_CC); zend_do_begin_class_member_function_call(&$, &$ TSRMLS_CC); }
  15. function_call_parameter_list
  16. ')' { zend_do_end_function_call(NULL, &$$, &$, , TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
  17. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name '(' { zend_do_begin_class_member_function_call(&$, &$ TSRMLS_CC); }
  18. function_call_parameter_list
  19. ')' { zend_do_end_function_call(NULL, &$$, &$, , TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
  20. | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(&$, BP_VAR_R, TSRMLS_CC); zend_do_begin_class_member_function_call(&$, &$ TSRMLS_CC); }
  21. function_call_parameter_list
  22. ')' { zend_do_end_function_call(NULL, &$$, &$, , TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
  23. | variable_without_objects '(' { zend_do_end_variable_parse(&$, BP_VAR_R, TSRMLS_CC); zend_do_begin_dynamic_function_call(&$, TSRMLS_CC); }
  24. function_call_parameter_list ')'
  25. { zend_do_end_function_call(&$, &$$, &$, , TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);}
  26. ;
  1. int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC) /* {{{ */
  2. {
  3. zend_function *function;
  4. char *lcname;
  5. char *is_compound = memchr(Z_STRVAL(function_name->u.constant), '\\', Z_STRLEN(function_name->u.constant));
  6.  
  7. zend_resolve_non_class_name(function_name, check_namespace TSRMLS_CC);
  8.  
  9. if (check_namespace && CG(current_namespace) && !is_compound) {
  10. /* We assume we call function from the current namespace
  11. if it is not prefixed. */
  12.  
  13. /* In run-time PHP will check for function with full name and
  14. internal function with short name */
  15. zend_do_begin_dynamic_function_call(function_name, TSRMLS_CC);
  16. return ;
  17. }
  18.  
  19. lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len); //将函数名称转化为小写,因为调用的时候,函数名可能是大写的
  20. if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+, (void **) &function)==FAILURE) ||
  21. ((CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS) &&
  22. (function->type == ZEND_INTERNAL_FUNCTION))) {
  23. zend_do_begin_dynamic_function_call(function_name, TSRMLS_CC);
  24. efree(lcname);
  25. return ; /* Dynamic */
  26. }
  27. efree(function_name->u.constant.value.str.val);
  28. function_name->u.constant.value.str.val = lcname;
  29.  
  30. zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
  31. zend_do_extended_fcall_begin(TSRMLS_C);
  32. return ;
  33. }
  1. ZEND_API int zend_stack_push(zend_stack *stack, const void *element, int size)
  2. {
  3. if (stack->top >= stack->max) { /* we need to allocate more memory */
  4. stack->elements = (void **) erealloc(stack->elements,
  5. (sizeof(void **) * (stack->max += STACK_BLOCK_SIZE)));
  6. if (!stack->elements) {
  7. return FAILURE;
  8. }
  9. }
  10. stack->elements[stack->top] = (void *) emalloc(size);
  11. memcpy(stack->elements[stack->top], element, size);
  12. return stack->top++;
  13. }
  14.  
  15. typedef struct _zend_stack {
  16. int top, max;
  17. void **elements;
  18. } zend_stack;
  1. void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
  2. {
  3. zend_op *opline;
  4.  
  5. if (is_method && function_name && function_name->op_type == IS_UNUSED) { //类方法
  6. /* clone */
  7. if (Z_LVAL(argument_list->u.constant) != ) {
  8. zend_error(E_WARNING, "Clone method does not require arguments");
  9. }
  10. opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)];
  11. } else { //普通方法
  12. opline = get_next_op(CG(active_op_array) TSRMLS_CC);
  13. if (!is_method && !is_dynamic_fcall && function_name->op_type==IS_CONST) {
  14. opline->opcode = ZEND_DO_FCALL; //设置执行时的handler
  15. SET_NODE(opline->op1, function_name); //设置左值为 方法的名称
  16. CALCULATE_LITERAL_HASH(opline->op1.constant);
  17. GET_CACHE_SLOT(opline->op1.constant);
  18. } else {
  19. opline->opcode = ZEND_DO_FCALL_BY_NAME;
  20. SET_UNUSED(opline->op1);
  21. }
  22. }
  23.  
  24. opline->result.var = get_temporary_variable(CG(active_op_array));
  25. opline->result_type = IS_VAR;
  26. GET_NODE(result, opline->result) ;
  27. SET_UNUSED(opline->op2);
  28.  
  29. zend_stack_del_top(&CG(function_call_stack));
  30. opline->extended_value = Z_LVAL(argument_list->u.constant);
  31. }
  1. #define CONSTANT_EX(op_array, op) \
  2. (op_array)->literals[op].constant
  3.  
  4. #define CONSTANT(op) \
  5. CONSTANT_EX(CG(active_op_array), op)
  6.  
  7. #define SET_NODE(target, src) do { \
  8. target ## _type = (src)->op_type; \
  9. if ((src)->op_type == IS_CONST) { \
  10. target.constant = zend_add_literal(CG(active_op_array), &(src)->u.constant TSRMLS_CC); \
  11. } else { \
  12. target = (src)->u.op; \
  13. } \
  14. } while ()
  15.  
  16. #define GET_NODE(target, src) do { \
  17. (target)->op_type = src ## _type; \
  18. if ((target)->op_type == IS_CONST) { \
  19. (target)->u.constant = CONSTANT(src.constant); \
  20. } else { \
  21. (target)->u.op = src; \
  22. (target)->EA = ; \
  23. } \
  24. } while ()
  1. static zend_uint get_temporary_variable(zend_op_array *op_array) /* {{{ */
  2. {
  3. return (op_array->T)++ * ZEND_MM_ALIGNED_SIZE(sizeof(temp_variable));
  4. }
  1. zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
  2. {
  3. zend_uint next_op_num = op_array->last++;
  4. zend_op *next_op;
  5.  
  6. if (next_op_num >= CG(context).opcodes_size) {
  7. if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
  8. /* we messed up */
  9. zend_printf("Ran out of opcode space!\n"
  10. "You should probably consider writing this huge script into a file!\n");
  11. zend_bailout();
  12. }
  13. CG(context).opcodes_size *= ;
  14. op_array_alloc_ops(op_array, CG(context).opcodes_size);
  15. }
  16.  
  17. next_op = &(op_array->opcodes[next_op_num]);
  18.  
  19. init_op(next_op TSRMLS_CC);
  20.  
  21. return next_op;
  22. }
  1. void init_op(zend_op *op TSRMLS_DC)
  2. {
  3. memset(op, , sizeof(zend_op)); //初始化
  4. op->lineno = CG(zend_lineno);
  5. SET_UNUSED(op->result);
  6. }
  1. typedef struct _zend_file_handle {
  2. zend_stream_type type;
  3. const char *filename;
  4. char *opened_path;
  5. union {
  6. int fd;
  7. FILE *fp;
  8. zend_stream stream;
  9. } handle;
  10. zend_bool free_filename;
  11. } zend_file_handle;
  1. void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC)
  2. {
  3. op_array->type = type;
  4.  
  5. if (CG(interactive)) {
  6. /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
  7. * will become invalid
  8. */
  9. initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE;
  10. }
  11.  
  12. op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
  13. *op_array->refcount = ;
  14. op_array->last = ;
  15. op_array->opcodes = NULL;
  16. op_array_alloc_ops(op_array, initial_ops_size);
  17.  
  18. op_array->last_var = ;
  19. op_array->vars = NULL;
  20.  
  21. op_array->T = ;
  22.  
  23. op_array->function_name = NULL;
  24. op_array->filename = zend_get_compiled_filename(TSRMLS_C);
  25. op_array->doc_comment = NULL;
  26. op_array->doc_comment_len = ;
  27.  
  28. op_array->arg_info = NULL;
  29. op_array->num_args = ;
  30. op_array->required_num_args = ;
  31.  
  32. op_array->scope = NULL;
  33.  
  34. op_array->brk_cont_array = NULL;
  35. op_array->try_catch_array = NULL;
  36. op_array->last_brk_cont = ;
  37.  
  38. op_array->static_variables = NULL;
  39. op_array->last_try_catch = ;
  40.  
  41. op_array->this_var = -;
  42.  
  43. op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:;
  44.  
  45. op_array->early_binding = -;
  46.  
  47. op_array->last_literal = ;
  48. op_array->literals = NULL;
  49.  
  50. op_array->run_time_cache = NULL;
  51. op_array->last_cache_slot = ;
  52.  
  53. memset(op_array->reserved, , ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
  54.  
  55. zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
  56. }

执行 opcode

  1. static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
  2. {
  3. USE_OPLINE
  4.  
  5. zval *fname = opline->op1.zv;
  6.  
  7. zend_ptr_stack_3_push(&EG(arg_types_stack), EX(fbc), EX(object), EX(called_scope));
  8.  
  9. if (CACHED_PTR(opline->op1.literal->cache_slot)) {
  10. EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot);
  11. } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) {
  1. //上面的zend_hash_quick_find很重要,从EG(function_table)中取出key为fname的value值,并将些值放入EX(fucntion_state)的function中
  2. SAVE_OPLINE();
  3. zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val);
  4. } else {
  5. CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); //放入原生态C数组中,因为会有第二次调用函数
  6. }
  7. EX(object) = NULL;
  8.  
  9. return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
  10. }
  1. static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS)
  2. {
  3. USE_OPLINE
  4. zend_bool should_change_scope = ;
  5. zend_function *fbc = EX(function_state).function;
  6.  
  7. SAVE_OPLINE();
  8. if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != )) {
  9. if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != )) {
  10. zend_error_noreturn(E_ERROR, "Cannot call abstract method %s::%s()", fbc->common.scope->name, fbc->common.function_name);
  11. CHECK_EXCEPTION();
  12. ZEND_VM_NEXT_OPCODE(); /* Never reached */
  13. }
  14. if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != )) {
  15. zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
  16. fbc->common.scope ? fbc->common.scope->name : "",
  17. fbc->common.scope ? "::" : "",
  18. fbc->common.function_name);
  19. }
  20. }
  21. if (fbc->common.scope &&
  22. !(fbc->common.fn_flags & ZEND_ACC_STATIC) &&
  23. !EX(object)) {
  24.  
  25. if (fbc->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
  26. /* FIXME: output identifiers properly */
  27. zend_error(E_STRICT, "Non-static method %s::%s() should not be called statically", fbc->common.scope->name, fbc->common.function_name);
  28. } else {
  29. /* FIXME: output identifiers properly */
  30. /* An internal function assumes $this is present and won't check that. So PHP would crash by allowing the call. */
  31. zend_error_noreturn(E_ERROR, "Non-static method %s::%s() cannot be called statically", fbc->common.scope->name, fbc->common.function_name);
  32. }
  33. }
  34.  
  35. if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) {
  36. should_change_scope = ;
  37. EX(current_this) = EG(This);
  38. EX(current_scope) = EG(scope);
  39. EX(current_called_scope) = EG(called_scope);
  40. EG(This) = EX(object);
  41. EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL;
  42. EG(called_scope) = EX(called_scope);
  43. }
  44.  
  45. zend_arg_types_stack_3_pop(&EG(arg_types_stack), &EX(called_scope), &EX(current_object), &EX(fbc));
  46. EX(function_state).arguments = zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
  47. LOAD_OPLINE();
  48.  
  49. if (fbc->type == ZEND_INTERNAL_FUNCTION) { //php内部函数
  50. temp_variable *ret = &EX_T(opline->result.var);
  51.  
  52. if (fbc->common.arg_info) {
  53. zend_uint i=;
  54. zval **p = (zval**)EX(function_state).arguments;
  55. ulong arg_count = opline->extended_value;
  56.  
  57. while (arg_count>) {
  58. zend_verify_arg_type(fbc, ++i, *(p-arg_count), TSRMLS_CC);
  59. arg_count--;
  60. }
  61. }
  62.  
  63. if (EXPECTED(EG(exception) == NULL)) {
  64. MAKE_STD_ZVAL(ret->var.ptr);
  65. ZVAL_NULL(ret->var.ptr);
  66. ret->var.ptr_ptr = &ret->var.ptr;
  67. ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != ;
  68.  
  69. if (!zend_execute_internal) {
  70. /* saves one function call if zend_execute_internal is not used */
  71. fbc->internal_function.handler(opline->extended_value, ret->var.ptr, (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) ? &ret->var.ptr : NULL, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
  72. } else {
  73. zend_execute_internal(execute_data, RETURN_VALUE_USED(opline) TSRMLS_CC);
  74. }
  75.  
  76. if (!RETURN_VALUE_USED(opline)) {
  77. zval_ptr_dtor(&ret->var.ptr);
  78. }
  79. } else if (RETURN_VALUE_USED(opline)) {
  80. EX_T(opline->result.var).var.ptr = NULL;
  81. }
  82. } else if (fbc->type == ZEND_USER_FUNCTION) { //php算定义的函数
  83. EX(original_return_value) = EG(return_value_ptr_ptr);
  84. EG(active_symbol_table) = NULL;
  85. EG(active_op_array) = &fbc->op_array;
  86. EG(return_value_ptr_ptr) = NULL;
  87. if (RETURN_VALUE_USED(opline)) {
  88. temp_variable *ret = &EX_T(opline->result.var);
  89.  
  90. ret->var.ptr = NULL;
  91. EG(return_value_ptr_ptr) = &ret->var.ptr;
  92. ret->var.ptr_ptr = &ret->var.ptr;
  93. ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != ;
  94. }
  95.  
  96. if (EXPECTED(zend_execute == execute)) {
  97. if (EXPECTED(EG(exception) == NULL)) {
  98. ZEND_VM_ENTER();
  99. }
  100. } else {
  101. zend_execute(EG(active_op_array) TSRMLS_CC);
  102. }
  103.  
  104. EG(opline_ptr) = &EX(opline);
  105. EG(active_op_array) = EX(op_array);
  106. EG(return_value_ptr_ptr) = EX(original_return_value);
  107. if (EG(active_symbol_table)) {
  108. if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
  109. zend_hash_destroy(EG(active_symbol_table));
  110. FREE_HASHTABLE(EG(active_symbol_table));
  111. } else {
  112. /* clean before putting into the cache, since clean
  113. could call dtors, which could use cached hash */
  114. zend_hash_clean(EG(active_symbol_table));
  115. *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
  116. }
  117. }
  118. EG(active_symbol_table) = EX(symbol_table);
  119. } else { /* ZEND_OVERLOADED_FUNCTION */
  120. MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr);
  121. ZVAL_NULL(EX_T(opline->result.var).var.ptr);
  122.  
  123. /* Not sure what should be done here if it's a static method */
  124. if (EXPECTED(EX(object) != NULL)) {
  125. Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, opline->extended_value, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC);
  126. } else {
  127. zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object");
  128. }
  129.  
  130. if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
  131. efree((char*)fbc->common.function_name);
  132. }
  133. efree(fbc);
  134.  
  135. if (!RETURN_VALUE_USED(opline)) {
  136. zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
  137. } else {
  138. Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr);
  139. Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, );
  140. EX_T(opline->result.var).var.fcall_returned_reference = ;
  141. EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
  142. }
  143. }
  144.  
  145. EX(function_state).function = (zend_function *) EX(op_array);
  146. EX(function_state).arguments = NULL;
  147.  
  148. if (should_change_scope) {
  149. if (EG(This)) {
  150. if (UNEXPECTED(EG(exception) != NULL) && IS_CTOR_CALL(EX(called_scope))) {
  151. if (IS_CTOR_USED(EX(called_scope))) {
  152. Z_DELREF_P(EG(This));
  153. }
  154. if (Z_REFCOUNT_P(EG(This)) == ) {
  155. zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
  156. }
  157. }
  158. zval_ptr_dtor(&EG(This));
  159. }
  160. EG(This) = EX(current_this);
  161. EG(scope) = EX(current_scope);
  162. EG(called_scope) = EX(current_called_scope);
  163. }
  164.  
  165. EX(object) = EX(current_object);
  166. EX(called_scope) = DECODE_CTOR(EX(called_scope));
  167.  
  168. zend_vm_stack_clear_multiple(TSRMLS_C);
  169.  
  170. if (UNEXPECTED(EG(exception) != NULL)) {
  171. zend_throw_exception_internal(NULL TSRMLS_CC);
  172. if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) {
  173. zval_ptr_dtor(&EX_T(opline->result.var).var.ptr);
  174. }
  175. HANDLE_EXCEPTION();
  176. }
  177.  
  178. ZEND_VM_NEXT_OPCODE();
  179. }
  1. void init_executor(TSRMLS_D) /* {{{ */
  2. {
  3. zend_init_fpu(TSRMLS_C);
  4.  
  5. INIT_ZVAL(EG(uninitialized_zval));
  6. /* trick to make uninitialized_zval never be modified, passed by ref, etc. */
  7. Z_ADDREF(EG(uninitialized_zval));
  8. INIT_ZVAL(EG(error_zval));
  9. EG(uninitialized_zval_ptr)=&EG(uninitialized_zval);
  10. EG(error_zval_ptr)=&EG(error_zval);
  11. zend_ptr_stack_init(&EG(arg_types_stack));
  12. /* destroys stack frame, therefore makes core dumps worthless */
  13. #if 0&&ZEND_DEBUG
  14. original_sigsegv_handler = signal(SIGSEGV, zend_handle_sigsegv);
  15. #endif
  16. EG(return_value_ptr_ptr) = NULL;
  17.  
  18. EG(symtable_cache_ptr) = EG(symtable_cache) - ;
  19. EG(symtable_cache_limit) = EG(symtable_cache) + SYMTABLE_CACHE_SIZE - ;
  20. EG(no_extensions) = ;
  21.  
  22. EG(function_table) = CG(function_table); //很重要
  23. EG(class_table) = CG(class_table);
  24.  
  25. EG(in_execution) = ;
  26. EG(in_autoload) = NULL;
  27. EG(autoload_func) = NULL;
  28. EG(error_handling) = EH_NORMAL;
  29.  
  30. zend_vm_stack_init(TSRMLS_C);
  31. zend_vm_stack_push((void *) NULL TSRMLS_CC);
  32.  
  33. zend_hash_init(&EG(symbol_table), , NULL, ZVAL_PTR_DTOR, );
  34. EG(active_symbol_table) = &EG(symbol_table);
  35.  
  36. zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_activator TSRMLS_CC);
  37. EG(opline_ptr) = NULL;
  38.  
  39. zend_hash_init(&EG(included_files), , NULL, NULL, );
  40.  
  41. EG(ticks_count) = ;
  42.  
  43. EG(user_error_handler) = NULL;
  44.  
  45. EG(current_execute_data) = NULL;
  46.  
  47. zend_stack_init(&EG(user_error_handlers_error_reporting));
  48. zend_ptr_stack_init(&EG(user_error_handlers));
  49. zend_ptr_stack_init(&EG(user_exception_handlers));
  50.  
  51. zend_objects_store_init(&EG(objects_store), );
  52.  
  53. EG(full_tables_cleanup) = ;
  54. #ifdef ZEND_WIN32
  55. EG(timed_out) = ;
  56. #endif
  57.  
  58. EG(exception) = NULL;
  59. EG(prev_exception) = NULL;
  60.  
  61. EG(scope) = NULL;
  62. EG(called_scope) = NULL;
  63.  
  64. EG(This) = NULL;
  65.  
  66. EG(active_op_array) = NULL;
  67.  
  68. EG(active) = ;
  69. EG(start_op) = NULL;
  70. }
  1. struct _zend_vm_stack {
  2. void **top;
  3. void **end;
  4. zend_vm_stack prev;
  5. };
  6.  
  7. static zend_always_inline void zend_vm_stack_push(void *ptr TSRMLS_DC)
  8. {
  9. ZEND_VM_STACK_GROW_IF_NEEDED();
  10. *(EG(argument_stack)->top++) = ptr;
  11. }

http://www.cnblogs.com/driftcloudy/p/3213504.html

函数传递参数入栈的原理

http://www.laruence.com/2010/01/03/1225.html

http://blog.sina.com.cn/s/blog_6ecf35840100m669.html 传值,传引用

http://www.phppan.com/2012/04/php-compiled-variable/ cv

本文主要参考“风雪之域”Laruence的文章。转载:http://www.laruence.com/2008/04/01/116.html

我们刚学php的时候,学到函数时,常会向里面传参数。比如function example($a,$b).那到底a和b的参数是怎么传入到example函数以及函数是怎么接受的呢,下面来为大家揭秘。

在 Zend/zend_language_scanner.l中我们会找到如下所示的代码:

<ST_IN_SCRipTING>

"function" {
    return T_FUNCTION;

}

它所表示的含义是function将会生成T_FUNCTION标记。T_FUNCTION标记只是用来定义函数的生命,标明这是一个函数,更多的东西则是参数,返回值等等。

当php等高级语言被编译成机器码时面临一个问题,cpu不能识别函数怎么传参,传的几个参数,传递参数的工作必须由函数调用者或函数本书来完成。当函数调用时,调用者依次把参数压栈,然后调用函数,调用后,在堆栈中取得数据,并进行计算。函数计算完成后,由调用者或者函数本身修改堆栈,使堆栈恢复原状。在参数传递过程中,有下列三个问题需要注意:

1:参数多余一个时,传递参数的顺序

2:函数调用后,谁来恢复堆栈

3:函数的返回值放在什么地方。

在高级语言中,通过函数调用规范来说明这几个问题。常见的调用规范有下面几个:

stdcall、cdecl、fastcall、thiscall、naked call

具体的调用规范大家可以参考具体的例子,这里只是把这几个问题的答案说出来

1:传递参数是由后到前传递。function example($a,$b).中,先把$b压栈再把$a压栈

2:由相关的规范决定

function 的声明的更多相关文章

  1. javascript:function 函数声明和函数表达式 详解

    函数声明(缩写为FD)是这样一种函数: 有一个特定的名称 在源码中的位置:要么处于程序级(Program level),要么处于其它函数的主体(FunctionBody)中 在进入上下文阶段创建 影响 ...

  2. 【JavaScript】[bind,call,apply] (function cal(){}());声明函数立即执行

    ---恢复内容开始--- 1.js 里函数调用有 4 种模式:方法调用.正常函数调用.构造器函数调用.apply/call 调用.同时,无论哪种函数调用除了你声明时定义的形参外,还会自动添加 2 个形 ...

  3. function——函数声明头的提升和预解析

    函数: 即function语句的集合,就是将多个语句封装到一起: 函数的执行要会自己遍历,遇见函数 a():执行语句,就要移交控制权,函数执行完毕之后,控制权又移交回来了! 函数的参数要罗列在func ...

  4. es6 - 一共有 6 种声明变量的方法(var, function, let, const, class, import)

    var命令和function命令声明的全局变量,依旧是顶层对象的属性:let命令.const命令.class命令声明的全局变量,不属于顶层对象的属性.也就是说,从 ES6 开始,全局变量将逐步与顶层对 ...

  5. javascript精雕细琢(一):var let const function声明的区别

    目录 引言 一.var 二.let 三.const 四.function 五.总结 引言        在学习javascript的过程中,变量是无时无刻不在使用的.那么相对应的,变量声明方法也如是. ...

  6. JavaScript 函数声明,函数表达式,匿名函数的区别,深入理解立即执行函数(function(){…})()

    function fnName(){xxxx}; // 函数声明:使用function关键字声明一个函数,在指定一个函数名. //例如:(正常,因为 提升 了函数声明,函数调用可以在函数声明之前) f ...

  7. 【repost】js中(function(){…})()立即执行函数写法理解

    摘要: javascript和其他编程语言相比比较随意,所以javascript代码中充满各种奇葩的写法,有时雾里看花,当然,能理解各型各色的写法也是对javascript语言特性更进一步的深入理解. ...

  8. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  9. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

随机推荐

  1. Facebook SDK

    <?php session_start(); header('Content-type:text/html; charset=UTF-8'); require_once './facebook- ...

  2. aix 上搭建node.js 环境

    下载nodejs:ibm-4.4.3.0-node-v4.4.3-aix-ppc64.bin IBM已经适配最新版本的node.js  :https://developer.ibm.com/node/ ...

  3. OPM与ILE编程模式的区别

    OPM与ILE编程模式的区别 OPM是传统编程模式,即一个可执行的程序只用一种语言编程:一个可执行程序只有一段程序代码组成:程序之间的调用关系是动态的调用关系. ILE是多语言开发集成编程模式,即一个 ...

  4. Hello Stacked Column Chart

    <navigation:Page xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/to ...

  5. RedHat6.4 用UDEV配置ASM所需磁盘

    同事在装一套RAC测试环境,结果发现原来用ASMLIB来配置磁盘,在安装GRID的时候,最终报错了,经过检查发现居然两边的磁盘不匹配.A机的sdb,sdc分别对应OCRVOL1,OCRVOL2,但是B ...

  6. Java注解处理器(转)

    Java中的注解(Annotation)是一个很神奇的东西,特别现在有很多Android库都是使用注解的方式来实现的.一直想详细了解一下其中的原理.很有幸阅读到一篇详细解释编写注解处理器的文章.本文的 ...

  7. python学习笔记17(动态类型)

    动态类型 在我们接触的对象中,有一类特殊的对象,是用于存储数据的,常见的该类对象包括各种数字,字符串,表,词典.在C语言中,我们称这样一些数据结构为变量,而在Python中,这些是对象. 对象是储存在 ...

  8. 简单3d RPG游戏 之 004 攻击(二)

    人物和怪物的攻击都有CD冷却,在PlayerAttack脚本中添加成员 //冷却倒计时 public float attackTimer; //CD冷却时间 public float coolDown ...

  9. httpmime-session 会话保持

    sesion在浏览器和web服务器直接是通过一个叫做name为sessionid的cookie来传递的,所以只要在每次数据请求时保持sessionid是同一个不变就可以用到web的session了,做 ...

  10. hdu 4101

    比赛的时候先是受以前一个圣神海的题目 用了两遍DFS 第一遍标记出围墙  第二遍求围墙外和每块围墙降为1所需的攻击次数  结果爆栈  改为BFS后AC DFS的加了一句这个 #pragma comme ...