创建最简单的对象(c 源码)

class Student{}

$s = new Student;

https://3v4l.org/RsEDf/vld#output
对应的 opcode:
NOP
NEW
DO_FCALL
ASSIGN
RETURN

程序编译完后生成 op_array,编译阶段的最终产物,也是执行阶段的输入;op_array属性中包含了编译好的opcodes

打印出的opcodes:

{{handler = 0x555555b4c981 <ZEND_NOP_SPEC_HANDLER>, op1 = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, op2 = {constant = 0, var = 0, num = 0, opline_num = 0,
      jmp_offset = 0}, result = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, extended_value = 0, lineno = 3, opcode = 0 '\000', op1_type = 8 '\b', op2_type = 8 '\b',
    result_type = 8 '\b'}, {handler = 0x555555b4fff2 <ZEND_NEW_SPEC_CONST_HANDLER>, op1 = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, op2 = {constant = 3, var = 3,
      num = 3, opline_num = 3, jmp_offset = 3}, result = {constant = 112, var = 112, num = 112, opline_num = 112, jmp_offset = 112}, extended_value = 0, lineno = 5, opcode = 68 'D',
    op1_type = 1 '\001', op2_type = 8 '\b', result_type = 4 '\004'}, {handler = 0x555555b4a2ac <ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER>, op1 = {constant = 8, var = 8, num = 8, opline_num = 8,
      jmp_offset = 8}, op2 = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, result = {constant = 2, var = 2, num = 2, opline_num = 2, jmp_offset = 2}, extended_value = 0,
    lineno = 5, opcode = 60 '<', op1_type = 8 '\b', op2_type = 8 '\b', result_type = 8 '\b'}, {handler = 0x555555ba3cd2 <ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUSED_HANDLER>, op1 = {constant = 80,
      var = 80, num = 80, opline_num = 80, jmp_offset = 80}, op2 = {constant = 112, var = 112, num = 112, opline_num = 112, jmp_offset = 112}, result = {constant = 3, var = 3, num = 3,
      opline_num = 3, jmp_offset = 3}, extended_value = 0, lineno = 5, opcode = 38 '&', op1_type = 16 '\020', op2_type = 4 '\004', result_type = 8 '\b'}, {
    handler = 0x555555b4f852 <ZEND_RETURN_SPEC_CONST_HANDLER>, op1 = {constant = 32, var = 32, num = 32, opline_num = 32, jmp_offset = 32}, op2 = {constant = 0, var = 0, num = 0,
      opline_num = 0, jmp_offset = 0}, result = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, extended_value = 4294967295, lineno = 6, opcode = 62 '>', op1_type = 1 '\001',
    op2_type = 8 '\b', result_type = 8 '\b'}, {handler = 0xa0, op1 = {constant = 1443046120, var = 1443046120, num = 1443046120, opline_num = 1443046120, jmp_offset = 1443046120}, op2 = {
      constant = 21845, var = 21845, num = 21845, opline_num = 21845, jmp_offset = 21845}, result = {constant = 0, var = 0, num = 0, opline_num = 0, jmp_offset = 0}, extended_value = 0,
    lineno = 570, opcode = 0 '\000', op1_type = 0 '\000', op2_type = 0 '\000', result_type = 0 '\000'}}

ZEND_NOP_SPEC_HANDLER:

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NOP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    ZEND_VM_NEXT_OPCODE();
}
#define ZEND_VM_NEXT_OPCODE() \
    ZEND_VM_NEXT_OPCODE_EX(0, 1)
#define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
    CHECK_SYMBOL_TABLES() \
    if (check_exception) { \
        OPLINE = EX(opline) + (skip); \
    } else { \
        OPLINE = opline + (skip); \
    } \
    ZEND_VM_CONTINUE()

ZEND_NEW_SPEC_CONST_HANDLER:

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
    zval *result;
    zend_function *constructor;
    zend_class_entry *ce;
    zend_execute_data *call;

    SAVE_OPLINE(); //EX(opline) = opline
    if (IS_CONST == IS_CONST) {
        //读取缓存       根据类名查找zend_class_entry
        ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
        if (UNEXPECTED(ce == NULL)) {
            ////第1步:根据类名查找zend_class_entry
            ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op1)), EX_CONSTANT(opline->op1) + 1, ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION);
            if (UNEXPECTED(ce == NULL)) {
                ZEND_ASSERT(EG(exception));
                HANDLE_EXCEPTION();
            }
            CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), ce);
        }
    } else if (IS_CONST == IS_UNUSED) {
        ce = zend_fetch_class(NULL, opline->op1.num);
        if (UNEXPECTED(ce == NULL)) {
            ZEND_ASSERT(EG(exception));
            HANDLE_EXCEPTION();
        }
    } else {
        ce = Z_CE_P(EX_VAR(opline->op1.var));
    }

    result = EX_VAR(opline->result.var);
    //2.创建&初始化一个这个类的对象           创建&初始化一个这个类的对象
    if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) {   //_object_and_properties_init
        HANDLE_EXCEPTION();
    }
    //第3步:获取构造方法=== 直接取zend_class_entry.constructor
    //get_constructor => zend_std_get_constructor()

    //#define Z_OBJ_HT(zval)                Z_OBJ(zval)->handlers
    //#define Z_OBJ_HT_P(zval_p)            Z_OBJ_HT(*(zval_p))

    //define Z_OBJ(zval)                    (zval).value.obj
    //#define Z_OBJ_P(zval_p)               Z_OBJ(*(zval_p))

    constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result));
    if (constructor == NULL) {
        if (UNEXPECTED(EG(exception))) {
            zval_ptr_dtor(result);
            HANDLE_EXCEPTION();
        }

        /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next
         * opcode is DO_FCALL in case EXT instructions are used. */
         //如果没有参数,则跳过DO_FCALL操作码。如果使用EXT指令,则检查下一个操作码是否为DO_FCALL
        if (EXPECTED(opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL)) {
            //此opcode之后还有传参、调用构造方法的操作
            //所以如果没有定义构造方法则直接跳过这些操作
            ZEND_VM_NEXT_OPCODE_EX(1, 2);
        }

        /* Perform a dummy function call */
        call = zend_vm_stack_push_call_frame(
            ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function,
            opline->extended_value, NULL, NULL);
    } else {
        if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!constructor->op_array.run_time_cache)) {
        //添加运行时方法的缓存
            init_func_run_time_cache(&constructor->op_array);
        }
        /* We are not handling overloaded classes right now */
        // 现在一个页面中不支持类的重新定义的,只支持方法的重写,覆盖定义
        //初始化调用构造函数的zend_execute_data
        call = zend_vm_stack_push_call_frame(
            ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_CTOR,
            constructor,
            opline->extended_value,
            ce,
            Z_OBJ_P(result));
        Z_ADDREF_P(result);
    }

    call->prev_execute_data = EX(call);
    EX(call) = call;
    ZEND_VM_NEXT_OPCODE();
}

1)zend_fetch_class_by_name:

zend_class_entry *zend_fetch_class_by_name(zend_string *class_name, const zval *key, int fetch_type) /* {{{ */
{
    zend_class_entry *ce;

    if (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) {
        //没有自动加载
        return zend_lookup_class_ex(class_name, key, 0);
        //有自动加载,
    } else if ((ce = zend_lookup_class_ex(class_name, key, 1)) == NULL) {
        if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) {
            if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
                //接口没有找到
                zend_throw_or_error(fetch_type, NULL, "Interface '%s' not found", ZSTR_VAL(class_name));
            } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
                //多继承的一种方式,其中一种没有找到
                zend_throw_or_error(fetch_type, NULL, "Trait '%s' not found", ZSTR_VAL(class_name));
            } else {
                //类没有找到
                zend_throw_or_error(fetch_type, NULL, "Class '%s' not found", ZSTR_VAL(class_name));
            }
        }
        return NULL;
    }
    return ce;
}

zend_lookup_class_ex

2) object_init_ex:对象初始化

 ZEND_API int _object_init_ex(zval *arg, zend_class_entry *class_type ZEND_FILE_LINE_DC) /* {{{ */
{
    return _object_and_properties_init(arg, class_type, 0 ZEND_FILE_LINE_RELAY_CC);
}

这个函数需要“properties”包含类中声明的所有属性,并且所有属性都是公共的。如果只有一个子集是给定的,或者类有受保护的成员,那么您需要通过调用zend_merge_properties()来分别合并属性。

//初始化对象的操作
ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties ZEND_FILE_LINE_DC) /* {{{ */
{
     //检查类是否可以实例化
    if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) {
        if (class_type->ce_flags & ZEND_ACC_INTERFACE) {
            //接口不能实例化
            zend_throw_error(NULL, "Cannot instantiate interface %s", ZSTR_VAL(class_type->name));
        } else if (class_type->ce_flags & ZEND_ACC_TRAIT) {
            //为实现多继承定义的 trait开头的,不能实例化
            zend_throw_error(NULL, "Cannot instantiate trait %s", ZSTR_VAL(class_type->name));
        } else {
            //抽象类不能实例化
            zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(class_type->name));
        }
        ZVAL_NULL(arg);
        Z_OBJ_P(arg) = NULL;
        return FAILURE;
    }

    if (UNEXPECTED(!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) {
        if (UNEXPECTED(zend_update_class_constants(class_type) != SUCCESS)) {
            ZVAL_NULL(arg);
            Z_OBJ_P(arg) = NULL;
            return FAILURE;
        }
    }

    //用户自定义的类create_object都是NULL
    //只有PHP几个内部的类有这个值,比如exception、error等
    if (class_type->create_object == NULL) {
        //分配一个对象     分配对象结构:zend_object ******
        ZVAL_OBJ(arg, zend_objects_new(class_type));
        if (properties) {
             //初始化成员属性****
            object_properties_init_ex(Z_OBJ_P(arg), properties);
        } else {
            object_properties_init(Z_OBJ_P(arg), class_type);
        }
    } else {
        //调用自定义的创建object的钩子函数
        ZVAL_OBJ(arg, class_type->create_object(class_type));
    }
    return SUCCESS;
}

zend_objects_new:

//注意:此操作并没有将属性拷贝到zend_object中:由object_properties_init()完成
ZEND_API zend_object *zend_objects_new(zend_class_entry *ce)
{
    //properties_table 是一个变长数组 存放非静态属性的值, 分配zend_object时需要加上非静态属性所占用的内存大小
    //根据普通非静态属性个数确定,如果没有定义__get()、__set()等魔术方法则占用内存就是: 属性数*sizeof(zval),
    //如果定义了这些魔术方法那么会多分配一个zval的空间 *******************
    //分配zend_object

    zend_object *object = emalloc(sizeof(zend_object) + zend_object_properties_size(ce));

    zend_object_std_init(object, ce);
    //设置对象的操作handler为std_object_handlers
    object->handlers = &std_object_handlers;
    return object;
}

zend_object_std_init:

ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce)
{
    zval *p, *end;

    GC_REFCOUNT(object) = 1;
    GC_TYPE_INFO(object) = IS_OBJECT;
    object->ce = ce;
    object->properties = NULL;
    //将object编号并插入EG(objects_store).object_buckets数组
    zend_objects_store_put(object);  //next
    p = object->properties_table;
    if (EXPECTED(ce->default_properties_count != 0)) {
        end = p + ce->default_properties_count;
        //值指向,写时复制;
        do {
            ZVAL_UNDEF(p);
            p++;
        } while (p != end);
    }
    if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
        GC_FLAGS(object) |= IS_OBJ_USE_GUARDS;
        ZVAL_UNDEF(p);
    }
}

zend_objects_store_put

3) get_constructor
zend_vm_stack_push_call_frame

ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER(本页最简单的代码中会跳过这个handler

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
    zend_execute_data *call = EX(call);
    zend_function *fbc = call->func;
    zend_object *object;
    zval *ret;

    SAVE_OPLINE();
    EX(call) = call->prev_execute_data;
    //deprecated弃用, 抽象的
    if (UNEXPECTED((fbc->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) != 0)) {
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_ABSTRACT) != 0)) {
            //不能调用抽象方法
            zend_throw_error(NULL, "Cannot call abstract method %s::%s()", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
            HANDLE_EXCEPTION();
        }
        if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
            //弃用的方法
            zend_error(E_DEPRECATED, "Function %s%s%s() is deprecated",
                fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "",
                fbc->common.scope ? "::" : "",
                ZSTR_VAL(fbc->common.function_name));
            if (UNEXPECTED(EG(exception) != NULL)) {
                HANDLE_EXCEPTION();
            }
        }
    }

    LOAD_OPLINE();  //LOAD_OPLINE() opline = EX(opline)
    //用户定义的类
    if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
        ret = NULL;
        if (0) {
            ret = EX_VAR(opline->result.var);
            ZVAL_NULL(ret);
        }
        //把当前的execute_data存储一下
        call->prev_execute_data = execute_data;
        //初始化当前方法的execute_data
        i_init_func_execute_data(call, &fbc->op_array, ret);

        if (EXPECTED(zend_execute_ex == execute_ex)) {
            ZEND_VM_ENTER();
        } else {
//#define ZEND_ADD_CALL_FLAG_EX(call_info, flag) do { \
        //  call_info |= ((flag) << ZEND_CALL_INFO_SHIFT); \
        //} while (0)

//#define ZEND_ADD_CALL_FLAG(call, flag) do { \
            //ZEND_ADD_CALL_FLAG_EX(Z_TYPE_INFO((call)->This), flag); \
    //} while (0)
            ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
            zend_execute_ex(call); //(*zend_execute_ex)(zend_execute_data *execute_data);
        }
    } else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {// 非用户定义的
        zval retval;

        call->prev_execute_data = execute_data;
        EG(current_execute_data) = call;

        /* function has typed arguments */
        //#define ZEND_ACC_HAS_TYPE_HINTS           0x10000000   hints提示
        if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
                //internal内部  verify验证  所有参数的类型
          && UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
            if (0) {
                ZVAL_UNDEF(EX_VAR(opline->result.var));
            }
            goto fcall_end;
        }

        ret = 0 ? EX_VAR(opline->result.var) : &retval;
        ZVAL_NULL(ret);

        if (!zend_execute_internal) {
            /* saves one function call if zend_execute_internal is not used */
            //如果没有使用zend_execute_internal,则保存一个函数调用
            fbc->internal_function.handler(call, ret);
        } else {
            zend_execute_internal(call, ret);
        }

#if ZEND_DEBUG
        if (!EG(exception) && call->func) {
            ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
                zend_verify_internal_return_type(call->func, ret));
            ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
                ? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
        }
#endif

        EG(current_execute_data) = call->prev_execute_data;
        zend_vm_stack_free_args(call);

        if (!0) {
            //销毁
            zval_ptr_dtor(ret);
        }

    } else { /* ZEND_OVERLOADED_FUNCTION */  //重载
        zval retval;

        ret = 0 ? EX_VAR(opline->result.var) : &retval;

        call->prev_execute_data = execute_data;

        if (UNEXPECTED(!zend_do_fcall_overloaded(fbc, call, ret))) {
            HANDLE_EXCEPTION();
        }

        if (!0) {
            zval_ptr_dtor(ret);
        }
    }

fcall_end:
    if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
        object = Z_OBJ(call->This);
#if 0
        if (UNEXPECTED(EG(exception) != NULL) && (opline->op1.num & ZEND_CALL_CTOR)) {
#else
        if (UNEXPECTED(EG(exception) != NULL) && (ZEND_CALL_INFO(call) & ZEND_CALL_CTOR)) {
#endif
            GC_REFCOUNT(object)--;
            //有异常
            zend_object_store_ctor_failed(object);
        }
        OBJ_RELEASE(object);
    }

    zend_vm_stack_free_call_frame(call);
    if (UNEXPECTED(EG(exception) != NULL)) {
        //有异常
        zend_throw_exception_internal(NULL);
        if (0) {
            zval_ptr_dtor(EX_VAR(opline->result.var));
        }
        HANDLE_EXCEPTION();
    }

    ZEND_VM_SET_OPCODE(opline + 1);
    ZEND_VM_CONTINUE();
}

i_init_func_execute_data

zend_do_fcall_overloaded

static zend_never_inline int zend_do_fcall_overloaded(zend_function *fbc, zend_execute_data *call, zval *ret) /* {{{ */
{
    zend_object *object;

    /* Not sure what should be done here if it's a static method */
    //如果它是一个静态方法,不知道这里应该做什么
    if (UNEXPECTED(Z_TYPE(call->This) != IS_OBJECT)) {
        //不是对象
        zend_vm_stack_free_args(call);
        if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
            zend_string_release(fbc->common.function_name);
        }
        efree(fbc);
        zend_vm_stack_free_call_frame(call);

        zend_throw_error(NULL, "Cannot call overloaded function for non-object");
        return 0;
    }

    object = Z_OBJ(call->This);

    ZVAL_NULL(ret);

    EG(current_execute_data) = call;
    //调用方法, 参数:方法,对象,参数,返回值
    object->handlers->call_method(fbc->common.function_name, object, call, ret);
    EG(current_execute_data) = call->prev_execute_data;

    zend_vm_stack_free_args(call);

    if (fbc->type == ZEND_OVERLOADED_FUNCTION_TEMPORARY) {
        zend_string_release(fbc->common.function_name);
    }
    efree(fbc);

    return 1;
}

ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUSED_HANDLER

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE
    zend_free_op free_op2;
    zval *value;
    zval *variable_ptr;

    SAVE_OPLINE(); //EX(opline) = opline
    //zval *ret = EX_VAR(var);
    //*should_free = ret;
    //return ret;
    value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
    //EX_VAR(var);第二个参数,| EX_VAR(n) END_CALL_VAR(execute_data, n)
    variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var);
    //不走
    if (IS_CV == IS_VAR && UNEXPECTED(Z_ISERROR_P(variable_ptr))) {
        zval_ptr_dtor_nogc(free_op2);
        if (UNEXPECTED(0)) {
            ZVAL_NULL(EX_VAR(opline->result.var));
        }
    } else {
        //赋值
        value = zend_assign_to_variable(variable_ptr, value, IS_VAR);
        if (UNEXPECTED(0)) {
            ZVAL_COPY(EX_VAR(opline->result.var), value);
        }
        //zend_assign_to_variable()总是处理op2,从不释放它
        /* zend_assign_to_variable() always takes care of op2, never free it! */
    }

    ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

zend_assign_to_variable

ZEND_RETURN_SPEC_CONST_HANDLER

  • step1: 首先根据类名去EG(class_table)中找到具体的类,即zend_class_entry
  • step2: 分配zend_object结构,一起分配的还有普通非静态属性值的内存
  • step3: 初始化对象的非静态属性,将属性值从zend_class_entry浅复制到对象中
  • step4: 查找当前类是否定义了构造函数,如果没有定义则跳过执行构造函数的opcode,否则为调用构造函数的执行进行一些准备工作(分配zend_execute_data)
  • step5: 实例化完成,返回新实例化的对象(如果返回的对象没有变量使用则直接释放掉了)
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!