php-5.6.26源代码 - include_once、require_once、include、require、eval 的opcode处理器

 

# ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER 实现在文件 php-5.6.26\Zend\zend_vm_execute.h
static int ZEND_FASTCALL  ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
    zend_op_array *new_op_array=NULL;

    zval *inc_filename;
    zval *tmp_inc_filename = NULL;
    zend_bool failure_retval=0;

    SAVE_OPLINE();
    inc_filename = opline->op1.zv; // 要include的文件

    if (inc_filename->type!=IS_STRING) {
        MAKE_STD_ZVAL(tmp_inc_filename);
        ZVAL_COPY_VALUE(tmp_inc_filename, inc_filename);
        zval_copy_ctor(tmp_inc_filename);
        convert_to_string(tmp_inc_filename);
        inc_filename = tmp_inc_filename;
    }

    if (opline->extended_value != ZEND_EVAL && strlen(Z_STRVAL_P(inc_filename)) != Z_STRLEN_P(inc_filename)) {
        if (opline->extended_value == ZEND_INCLUDE_ONCE || opline->extended_value == ZEND_INCLUDE) {
            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
        } else {
            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
        }
    } else {
        switch (opline->extended_value) {
            // include_once 和 require_once
            case ZEND_INCLUDE_ONCE: // 只 included 一次
            case ZEND_REQUIRE_ONCE: {
                    zend_file_handle file_handle;
                    char *resolved_path;

                    resolved_path = zend_resolve_path(Z_STRVAL_P(inc_filename), Z_STRLEN_P(inc_filename) TSRMLS_CC); // 解析文件路径
                    if (resolved_path) {
                        failure_retval = zend_hash_exists(&EG(included_files), resolved_path, strlen(resolved_path)+1); // 是否已经 included
                    } else {
                        resolved_path = Z_STRVAL_P(inc_filename);
                    }

                    if (failure_retval) { // 如已经 included
                        /* do nothing, file already included */
                    } else if (SUCCESS == zend_stream_open(resolved_path, &file_handle TSRMLS_CC)) { // 尝试打开文件流

                        if (!file_handle.opened_path) {
                            file_handle.opened_path = estrdup(resolved_path);
                        }

                        if (zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path, strlen(file_handle.opened_path)+1)==SUCCESS) { // 添加到已经 included
                            // zend_compile_file == compile_file
                            new_op_array = zend_compile_file(&file_handle, (opline->extended_value==ZEND_INCLUDE_ONCE?ZEND_INCLUDE:ZEND_REQUIRE) TSRMLS_CC); //  编译文件,获取新的opcode列表
                            {
                                # compile_file 实现在文件 php-5.6.26\Zend\zend_language_scanner.c
                                ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
                                {
                                    zend_lex_state original_lex_state;
                                    zend_op_array *op_array = (zend_op_array *) emalloc(sizeof(zend_op_array));
                                    zend_op_array *original_active_op_array = CG(active_op_array); // 保存 op_code 现场(保存现场)
                                    zend_op_array *retval=NULL;
                                    int compiler_result;
                                    zend_bool compilation_successful=0;
                                    znode retval_znode;
                                    zend_bool original_in_compilation = CG(in_compilation);
                                
                                    retval_znode.op_type = IS_CONST;
                                    INIT_PZVAL(&retval_znode.u.constant);
                                    ZVAL_LONG(&retval_znode.u.constant, 1);
                                
                                    zend_save_lexical_state(&original_lex_state TSRMLS_CC);  // 保存词法分析器的状态(保存现场)
                                
                                    retval = op_array; /* success oriented */
                                
                                    if (open_file_for_scanning(file_handle TSRMLS_CC)==FAILURE) { // 打开文件、设置扫描器的指针
                                        if (type==ZEND_REQUIRE) {
                                            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename TSRMLS_CC); // 发送失败信息
                                            zend_bailout(); // !!! require、require_once 会抛出异常
                                        } else {
                                            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename TSRMLS_CC);
                                            // 没有抛出异常
                                        }
                                        compilation_successful=0;
                                    } else {
                                        // 扫描后、初始化 op_array
                                        init_op_array(op_array, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);  // 1、初始化一些数据、申请空间  2、迭代调用所有 zend_extensions 扩展的 op_array_ctor 函数
                                        CG(in_compilation) = 1;  // 是否处于汇编状态
                                        CG(active_op_array) = op_array; // 操作码数组
                                        zend_stack_push(&CG(context_stack), (void *) &CG(context), sizeof(CG(context))); // 把当前上下文入栈
                                        zend_init_compiler_context(TSRMLS_C); // 初始化编译器上下文
                                        compiler_result = zendparse(TSRMLS_C); // 开始解析  zendparse == phpparse == yyparse
                                        zend_do_return(&retval_znode, 0 TSRMLS_CC); // 返回
                                        CG(in_compilation) = original_in_compilation;  // 还原现场
                                        if (compiler_result != 0) { /* parser error */
                                            zend_bailout(); // !!! 抛出异常
                                        }
                                        compilation_successful=1;  // 汇编成功
                                    }
                                
                                    if (retval) {
                                        CG(active_op_array) = original_active_op_array; // 还原原来 op_code 现场(还原现场)
                                        if (compilation_successful) {  // 汇编成功
                                            pass_two(op_array TSRMLS_CC); // !!!! 给每个op_code注册“op_code处理器”
                                            zend_release_labels(0 TSRMLS_CC);
                                        } else {
                                            efree(op_array);
                                            retval = NULL;
                                        }
                                    }
                                    zend_restore_lexical_state(&original_lex_state TSRMLS_CC);  // 还原原来词法解析器的状态(还原现场)
                                    return retval;
                                }
                                                                
                            }
                            zend_destroy_file_handle(&file_handle TSRMLS_CC);
                        } else {
                            zend_file_handle_dtor(&file_handle TSRMLS_CC);
                            failure_retval=1;
                        }
                    } else {
                        if (opline->extended_value == ZEND_INCLUDE_ONCE) { // include_once 执行失败,消息通知
                            zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
                        } else { // require_once 执行失败,消息通知
                            zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, Z_STRVAL_P(inc_filename) TSRMLS_CC);
                        }
                    }
                    if (resolved_path != Z_STRVAL_P(inc_filename)) {
                        efree(resolved_path);
                    }
                }
                break;
            // include 和 require
            case ZEND_INCLUDE: // 可以 included 多次
            case ZEND_REQUIRE:
                new_op_array = compile_filename(opline->extended_value, inc_filename TSRMLS_CC); // 编译文件,获取新的opcode列表
                break;
            // eval
            case ZEND_EVAL: { // 使用的是 eval 指令
                    char *eval_desc = zend_make_compiled_string_description("eval()'d code" TSRMLS_CC);

                    new_op_array = zend_compile_string(inc_filename, eval_desc TSRMLS_CC); // 编译后,获取新的opcode列表
                    efree(eval_desc);
                }
                break;
            EMPTY_SWITCH_DEFAULT_CASE()
        }
    }
    if (tmp_inc_filename) {
        zval_ptr_dtor(&tmp_inc_filename);
    }

    if (UNEXPECTED(EG(exception) != NULL)) {
        HANDLE_EXCEPTION();
    } else if (EXPECTED(new_op_array != NULL)) {
        EX(original_return_value) = EG(return_value_ptr_ptr);
        EG(active_op_array) = new_op_array;
        if (RETURN_VALUE_USED(opline)) {
            EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr;
            EG(return_value_ptr_ptr) = EX_T(opline->result.var).var.ptr_ptr;
        } else {
            EG(return_value_ptr_ptr) = NULL;
        }

        EX(function_state).function = (zend_function *) new_op_array;
        EX(object) = NULL;

        if (!EG(active_symbol_table)) {
            zend_rebuild_symbol_table(TSRMLS_C);
        }

        if (EXPECTED(zend_execute_ex == execute_ex)) {
            ZEND_VM_ENTER();
        } else {
            zend_execute(new_op_array TSRMLS_CC);  // 执行opcode列表
            {
                # zend_execute 实现在文件 php-5.6.26\Zend\zend_vm_execute.h
                ZEND_API void zend_execute(zend_op_array *op_array TSRMLS_DC)
                {
                    if (EG(exception)) {
                        return;
                    } 
                    zend_execute_ex(i_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC) TSRMLS_CC); // zend_execute_ex = execute_ex
                }
            }
        }

        EX(function_state).function = (zend_function *) EX(op_array);

        EG(opline_ptr) = &EX(opline);
        EG(active_op_array) = EX(op_array);
        EG(return_value_ptr_ptr) = EX(original_return_value);
        destroy_op_array(new_op_array TSRMLS_CC);
        efree(new_op_array);
        if (UNEXPECTED(EG(exception) != NULL)) {
            zend_throw_exception_internal(NULL TSRMLS_CC);
            HANDLE_EXCEPTION();
        }

    } else if (RETURN_VALUE_USED(opline)) {
        zval *retval;

        ALLOC_ZVAL(retval);
        ZVAL_BOOL(retval, failure_retval);
        INIT_PZVAL(retval);
        EX_T(opline->result.var).var.ptr = retval;
    }
    ZEND_VM_NEXT_OPCODE();
}

 

转载于:https://www.cnblogs.com/xiaoyaogege/p/8629074.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值