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