php源码-异常throw处理过程-02

php代码中的 throw 被编译完后的opcode 如下

opcode: 108 ZEND_THROW , index:2369 ZEND_THROW_SPEC_VAR_HANDLER

其中 ZEND_THROW_SPEC_VAR_HANDLER 最终会通过

zend_throw_exception_internal() 来抛出异常

ZEND_API ZEND_COLD void zend_throw_exception_internal(zval *exception) /* {{{ */
{
    if (!EG(current_execute_data)->func ||
        !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
        EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION) {
        /* no need to rethrow the exception */
        return;
    }
    EG(opline_before_exception) = EG(current_execute_data)->opline;
    EG(current_execute_data)->opline = EG(exception_op);
}

这里的关键代码是这句 EG(current_execute_data)->opline->opcode == ZEND_HANDLE_EXCEPTION

ZEND_HANDLE_EXCEPTION 对应的 handler是 ZEND_HANDLE_EXCEPTION_SPEC_HANDLER

执行的是常见的try catch 捕获跳转流程, 参考php源码-try、catch过程-原理

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    uint32_t throw_op_num = EG(opline_before_exception) - EX(func)->op_array.opcodes;
    int i, current_try_catch_offset = -1;

    {
        const zend_op *exc_opline = EG(opline_before_exception);
        if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
            && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
            /* exceptions thrown because of loop var destruction on return/break/...
             * are logically thrown at the end of the foreach loop, so adjust the
             * throw_op_num.
             */
            throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
        }
    }

    /* Find the innermost try/catch/finally the exception was thrown in */
    for (i = 0; i < EX(func)->op_array.last_try_catch; i++) {
        zend_try_catch_element *try_catch = &EX(func)->op_array.try_catch_array[i];
        if (try_catch->try_op > throw_op_num) {
            /* further blocks will not be relevant... */
            break;
        }
        if (throw_op_num < try_catch->catch_op || throw_op_num < try_catch->finally_end) {
            current_try_catch_offset = i;
        }
    }

    cleanup_unfinished_calls(execute_data, throw_op_num);

    ZEND_VM_TAIL_CALL(zend_dispatch_try_catch_finally_helper_SPEC(current_try_catch_offset, throw_op_num ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));
}

你可能感兴趣的:(php源码-异常throw处理过程-02)