设为首页 收藏本站
查看: 809|回复: 0

[经验分享] 原:PHP内核研究 函数的定义

[复制链接]

尚未签到

发表于 2017-4-4 09:33:13 | 显示全部楼层 |阅读模式
声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

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

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


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

function hello($str){

echo $str;

}

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

[c]
function:
        T_FUNCTION { $$.u.opline_num = CG(zend_lineno); }
;
[/c]

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

而真正parse的地方在哪里?我找了很久没找到,不得已 Google了一下,才知道是在这里



[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]

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看看,

比较长 一点点来看

[c]
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;
}
[/c]



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


[c]
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;
[/c]



初始化op_array

生成 zend_op

生成的中间码 ZEND_DECLARE_FUNCTION

更新函数表function_table

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

下一节详细介绍 函数的参数.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-359908-1-1.html 上篇帖子: PHP开发搜索引擎之技术核心 下篇帖子: PHP超牛邮件发送类
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表