fjqzyc 发表于 2017-4-4 09:33:13

原:PHP内核研究 函数的定义

声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

博客地址:PHP技术博客在CSDN也会同步更新的哦.

欢迎转载,转载请注明出处


PHP中,函数的定义 是用关键字 function来定义的.

function hello($str){

echo $str;

}

在/zend/zend_language_parse.y中找到 关键字 T_FUNCTION


function:
      T_FUNCTION { $$.u.opline_num = CG(zend_lineno); }
;


发现这个只是用来保存当前函数设置的位置的..

而真正parse的地方在哪里?我找了很久没找到,不得已 Google了一下,才知道是在这里
http://imsiren.com/wp-includes/js/tinymce/plugins/wordpress/img/trans.gif



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); }
;


is_reference :是引用吗?

T_STRING :我们定义的函数名 ,等于hello

zend_do_begin_function_declaration:开始声明函数.

parameter_list :是参数表

inner_statement_list :函数体语句

zend_do_end_function_declaration:结束声明

一个一个来 先进 zend_do_begin_function_declaration看看,

比较长 一点点来看


void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
{
      zend_op_array op_array;
      char *name = function_name->u.constant.value.str.val; //函数名
      int name_len = function_name->u.constant.value.str.len;//函数名长度
      int function_begin_line = function_token->u.opline_num;//函数定义的位置
      zend_uint fn_flags;
      char *lcname;
      zend_bool orig_interactive;
      if (is_method) { //是类的方法? 这里不涉及到类的方法的内容 所以暂时跳过
                if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
                        if ((Z_LVAL(fn_flags_znode->u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC))) {
                        }
                        Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
                }
                fn_flags = Z_LVAL(fn_flags_znode->u.constant); /* must be done *after* the above check */
      } else {
                fn_flags = 0;
      }
      //类相关 跳过
      if ((fn_flags & ZEND_ACC_STATIC) && (fn_flags & ZEND_ACC_ABSTRACT) && !(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)) {
         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));
      }
      //转换为小写
      lcname = zend_str_tolower_dup(name, name_len);

      orig_interactive = CG(interactive);
      CG(interactive) = 0;
      //初始化zend_op_array
      /*要特别说明一下 在PHP里面 函数有两种一种是自定义函数:ZEND_USER_FUNCTION,
         *一种是内置函数ZEND_INTERNAL_FUNCTION,这里我们是自定义函数所以 类型为ZEND_USER_FUNCTION
          */
      init_op_array(&op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
      CG(interactive) = orig_interactive;

      op_array.function_name = name; //函数名称
      op_array.return_reference = return_reference; //是否是引用函数
      op_array.fn_flags |= fn_flags; //可能是标示声明为类的方法
      op_array.pass_rest_by_reference = 0; //所有参数都强制为引用?
      op_array.prototype = NULL;//

      op_array.line_start = zend_get_compiled_lineno(TSRMLS_C);//开始行
      if (is_method) {//类的方法 以下....省略

      } else {//到这里 ,用户函数
                //生成一个 zend_op
                zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

                if (CG(current_namespace)) { //5.3新特性 支持命名空间
                        /* Prefix function name with current namespcae name */
                        znode tmp;

                        tmp.u.constant = *CG(current_namespace);
                        zval_copy_ctor(&tmp.u.constant);
                        zend_do_build_namespace_name(&tmp, &tmp, function_name TSRMLS_CC);
                        op_array.function_name = Z_STRVAL(tmp.u.constant);
                        efree(lcname);
                        name_len = Z_STRLEN(tmp.u.constant);
                        lcname = zend_str_tolower_dup(Z_STRVAL(tmp.u.constant), name_len);
                }
                //生成的中间代码
                opline->opcode = ZEND_DECLARE_FUNCTION;
                //类型
                opline->op1.op_type = IS_CONST;
                build_runtime_defined_function_key(&opline->op1.u.constant, lcname, name_len TSRMLS_CC);
                opline->op2.op_type = IS_CONST;
                opline->op2.u.constant.type = IS_STRING;
                opline->op2.u.constant.value.str.val = lcname;
                opline->op2.u.constant.value.str.len = name_len;
                Z_SET_REFCOUNT(opline->op2.u.constant, 1);
                opline->extended_value = ZEND_DECLARE_FUNCTION;
               //更新函数表的HashTable
               zend_hash_update(CG(function_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
      }

      if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
                zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

                opline->opcode = ZEND_EXT_NOP;
                opline->lineno = function_begin_line;
                SET_UNUSED(opline->op1);
                SET_UNUSED(opline->op2);
      }

      {
                /* Push a seperator to the switch and foreach stacks */
                zend_switch_entry switch_entry;

                switch_entry.cond.op_type = IS_UNUSED;
                switch_entry.default_case = 0;
                switch_entry.control_var = 0;

                zend_stack_push(&CG(switch_cond_stack), (void *) &switch_entry, sizeof(switch_entry));

                {
                        /* Foreach stack separator */
                        zend_op dummy_opline;

                        dummy_opline.result.op_type = IS_UNUSED;
                        dummy_opline.op1.op_type = IS_UNUSED;

                        zend_stack_push(&CG(foreach_copy_stack), (void *) &dummy_opline, sizeof(zend_op));
                }
      }

      if (CG(doc_comment)) {
                CG(active_op_array)->doc_comment = CG(doc_comment);
                CG(active_op_array)->doc_comment_len = CG(doc_comment_len);
                CG(doc_comment) = NULL;
                CG(doc_comment_len) = 0;
      }

      zend_stack_push(&CG(labels_stack), (void *) &CG(labels), sizeof(HashTable*));
      CG(labels) = NULL;
}




保存自定义函数的结构如下



typedef union _zend_function {
    zend_uchar type;    /* MUST be the first element of this struct! */

    struct {
      zend_uchar type;/* never used */
      char *function_name; //函数名称
      zend_class_entry *scope;
      zend_uint fn_flags;
      union _zend_function *prototype;
      zend_uint num_args; //参数个数
      zend_uint required_num_args;
      zend_arg_info *arg_info;
      zend_bool pass_rest_by_reference;
      unsigned char return_reference;
    } common;

    zend_op_array op_array;
    zend_internal_function internal_function;
} zend_function;




初始化op_array

生成 zend_op

生成的中间码 ZEND_DECLARE_FUNCTION

更新函数表function_table

这样 函数的定义就完了..

下一节详细介绍 函数的参数.
页: [1]
查看完整版本: 原:PHP内核研究 函数的定义