// opcode处理器 --- ZEND_DO_FCALL_SPEC_CONST_HANDLER实现在 php-5.6.26\Zend\zend_vm_execute.h static int ZEND_FASTCALL ZEND_DO_FCALL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zval *fname = opline->op1.zv; call_slot *call = EX(call_slots) + opline->op2.num; if (CACHED_PTR(opline->op1.literal->cache_slot)) { EX(function_state).function = CACHED_PTR(opline->op1.literal->cache_slot); } else if (UNEXPECTED(zend_hash_quick_find(EG(function_table), Z_STRVAL_P(fname), Z_STRLEN_P(fname)+1, Z_HASH_P(fname), (void **) &EX(function_state).function)==FAILURE)) { // 查找函数,把函数指针放入 EX(function_state).function SAVE_OPLINE(); zend_error_noreturn(E_ERROR, "Call to undefined function %s()", fname->value.str.val); } else { CACHE_PTR(opline->op1.literal->cache_slot, EX(function_state).function); } call->fbc = EX(function_state).function; // 函数信息指针 call->object = NULL; call->called_scope = NULL; call->num_additional_args = 0; call->is_ctor_call = 0; EX(call) = call; // ZEND_OPCODE_HANDLER_ARGS_PASSTHRU ---> execute_data TSRMLS_CC return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); // zend_do_fcall_common_helper_SPEC(execute_data) { ... if (fbc->type == ZEND_INTERNAL_FUNCTION) { // 内建函数 --- 执行的是函数指针(扩展中定义的函数) if (fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { zend_uint i; void **p = EX(function_state).arguments - num_args; for (i = 0; i < num_args; ++i, ++p) { zend_verify_arg_type(fbc, i + 1, (zval *) *p, 0, NULL TSRMLS_CC); } } if (EXPECTED(EG(exception) == NULL)) { temp_variable *ret = &EX_T(opline->result.var); MAKE_STD_ZVAL(ret->var.ptr); ZVAL_NULL(ret->var.ptr); ret->var.ptr_ptr = &ret->var.ptr; ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; if (!zend_execute_internal) { // !!! 执行函数 /* saves one function call if zend_execute_internal is not used */ fbc->internal_function.handler(num_args, ret->var.ptr, &ret->var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); // 调用扩展模块的函数 } else { zend_execute_internal(execute_data, NULL, RETURN_VALUE_USED(opline) TSRMLS_CC); } if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(&ret->var.ptr); } } else if (RETURN_VALUE_USED(opline)) { EX_T(opline->result.var).var.ptr = NULL; } } else if (fbc->type == ZEND_USER_FUNCTION) { // 用户定义的函数 --- 执行的opcode temp_variable *ret = &EX_T(opline->result.var); EX(original_return_value) = EG(return_value_ptr_ptr); EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; // !!! 用户函数编译出来的操作码 EG(return_value_ptr_ptr) = NULL; if (RETURN_VALUE_USED(opline)) { ret->var.ptr = NULL; EG(return_value_ptr_ptr) = &ret->var.ptr; ret->var.ptr_ptr = &ret->var.ptr; ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0; } if (UNEXPECTED((EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) { if (RETURN_VALUE_USED(opline)) { ret->var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC); ret->var.fcall_returned_reference = 0; } } else if (EXPECTED(zend_execute_ex == execute_ex)) { if (EXPECTED(EG(exception) == NULL)) { ZEND_VM_ENTER(); } } else { zend_execute(EG(active_op_array) TSRMLS_CC); // 执行操作码 } EG(opline_ptr) = &EX(opline); EG(active_op_array) = EX(op_array); EG(return_value_ptr_ptr) = EX(original_return_value); if (EG(active_symbol_table)) { zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC); } EG(active_symbol_table) = EX(symbol_table); } else { /* ZEND_OVERLOADED_FUNCTION */ MAKE_STD_ZVAL(EX_T(opline->result.var).var.ptr); ZVAL_NULL(EX_T(opline->result.var).var.ptr); /* Not sure what should be done here if it's a static method */ if (EXPECTED(EX(object) != NULL)) { // 调用对象方法 Z_OBJ_HT_P(EX(object))->call_method(fbc->common.function_name, num_args, EX_T(opline->result.var).var.ptr, &EX_T(opline->result.var).var.ptr, EX(object), RETURN_VALUE_USED(opline) TSRMLS_CC); } else { zend_error_noreturn(E_ERROR, "Cannot call overloaded function for non-object"); } if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) { efree((char*)fbc->common.function_name); } efree(fbc); if (!RETURN_VALUE_USED(opline)) { zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); } else { Z_UNSET_ISREF_P(EX_T(opline->result.var).var.ptr); Z_SET_REFCOUNT_P(EX_T(opline->result.var).var.ptr, 1); EX_T(opline->result.var).var.fcall_returned_reference = 0; EX_T(opline->result.var).var.ptr_ptr = &EX_T(opline->result.var).var.ptr; } } ... EX(call)--; zend_vm_stack_clear_multiple(0 TSRMLS_CC); if (UNEXPECTED(EG(exception) != NULL)) { zend_throw_exception_internal(NULL TSRMLS_CC); // 抛异常 if (RETURN_VALUE_USED(opline) && EX_T(opline->result.var).var.ptr) { zval_ptr_dtor(&EX_T(opline->result.var).var.ptr); } HANDLE_EXCEPTION(); } ZEND_VM_NEXT_OPCODE(); ... } }