• php 类 成员变量 $this->name='abc'


    <?php
    class test
    {
       public function getName()
      {
          $this->name='abc';
         echo $this->name;  
       }            
    }
    $a=new test();
    $a->getName();

     

    1.$this->name='abc'对应的BNF范式

    expr_without_variable:
            variable '=' expr        { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
    ;
    variable:
            base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); }
                object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties
                { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); }
    ;
    base_variable_with_function_calls:
           compound_variable            { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
    ;
    compound_variable:
            T_VARIABLE            { $$ = $1; }
    ;
    object_property:
            object_dim_list { $$ = $1; }
    ;
    object_dim_list:
            variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);}
    ;
    variable_name:
            T_STRING     { $$ = $1; }

     

     

    理解版

    expr_without_variable:
            variable '=' expr        { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); }
    ;
    variable:
            base_variable T_OBJECT_OPERATOR object_property  method_or_not variable_properties
               
    ;
    base_variable:
           T_VARIABLE            { fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
    ;
    
    object_property:
            T_STRING {  zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);}
    ;

     

     

    2. 对于 $this 产生 opcode ZEND_FETCH_W

    void fetch_simple_variable_ex(znode *result, znode *varname, int bp, zend_uchar op TSRMLS_DC) /* {{{ */
    {
        zend_op opline;
        zend_op *opline_ptr;
        zend_llist *fetch_list_ptr;
    
        if (varname->op_type == IS_CONST) {
            ulong hash;
    
            if (Z_TYPE(varname->u.constant) != IS_STRING) {
                convert_to_string(&varname->u.constant);
            }
    
            hash = str_hash(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant));
    //如果变量名不是this,那么在active_symbole_table中插入一个key
    if (!zend_is_auto_global_quick(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), hash TSRMLS_CC) && !(Z_STRLEN(varname->u.constant) == (sizeof("this")-1) && !memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this") - 1)) && (CG(active_op_array)->last == 0 || CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE)) { result->op_type = IS_CV; result->u.op.var = lookup_cv(CG(active_op_array), Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant), hash TSRMLS_CC); Z_STRVAL(varname->u.constant) = (char*)CG(active_op_array)->vars[result->u.op.var].name; result->EA = 0; return; } } //如果变量名是$this,则生成新的opcode opline_ptr = get_next_op(CG(active_op_array) TSRMLS_CC); opline_ptr->opcode = op; opline_ptr->result_type = IS_VAR; opline_ptr->result.var = get_temporary_variable(CG(active_op_array)); SET_NODE(opline_ptr->op1, varname); GET_NODE(result, opline_ptr->result); SET_UNUSED(opline_ptr->op2); opline_ptr->extended_value = ZEND_FETCH_LOCAL; zend_llist_add_element(fetch_list_ptr, opline_ptr); }

     

    3.对于 $this->name修改上面的opcode 为 ZEND_FETCH_OBJ_W

    void zend_do_fetch_property(znode *result, znode *object, const znode *property TSRMLS_DC) /* {{{ */
    {
          zend_llist *fetch_list_ptr;
             if (fetch_list_ptr->count == 1) {
                    zend_llist_element *le = fetch_list_ptr->head;
                    zend_op *opline_ptr = (zend_op *) le->data;
    
                    if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) {
                            zend_del_literal(CG(active_op_array), opline_ptr->op1.constant);
                            SET_UNUSED(opline_ptr->op1); /* this means $this for objects */
                            SET_NODE(opline_ptr->op2, property);
                            /* if it was usual fetch, we change it to object fetch */
                            switch (opline_ptr->opcode) {
                                    case ZEND_FETCH_W:
                                            opline_ptr->opcode = ZEND_FETCH_OBJ_W;
    
                            }                  
                            return;
                    }
            }
    }

     

    4.对于$this->name='abc' ,执行方法zend_do_assign,设置为zend_ASSIGN_OBJ

    void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {{{ */
    {
        last_op_number = get_next_op_number(CG(active_op_array));
            if (variable->op_type == IS_VAR) {
                    zend_op *last_op;
                    last_op = &CG(active_op_array)->opcodes[last_op_number-n-1];  
                    if (last_op->result_type == IS_VAR && last_op->result.var == variable->u.op.var) {
                            if (last_op->opcode == ZEND_FETCH_OBJ_W) {
                                    last_op->opcode = ZEND_ASSIGN_OBJ;
                                    zend_do_op_data(opline, value TSRMLS_CC);
                                    SET_UNUSED(opline->result);
                                    GET_NODE(result, last_op->result);
                                    return;
                            }
                    }
            }   
    }

     5.执行ZEND_ASSIGN_OBJ

    static int ZEND_FASTCALL  ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
    
        zval **object_ptr;
        zval *property_name;
        object_ptr = _get_obj_zval_ptr_ptr_unused(TSRMLS_C);
        property_name = opline->op2.zv;
        zend_assign_to_object(RETURN_VALUE_USED(opline)?&EX_T(opline->result.var).var.ptr:NULL, object_ptr, property_name, (opline+1)->op1_type, &(opline+1)->op1, execute_data, ZEND_ASSIGN_OBJ, ((IS_CONST == IS_CONST) ? opline->op2.literal : NULL) TSRMLS_CC);
        
    }

     

    static inline void zend_assign_to_object(zval **retval, zval **object_ptr, zval *property_name, int value_type, znode_op *value_op, const zend_execute_data *execute_data, int opcode, const zend_literal *key TSRMLS_DC)
    {
        zval *object = *object_ptr;
        Z_OBJ_HT_P(object)->write_property(object, property_name, value, key TSRMLS_CC);
    }
    
    ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
    {
        zend_object *zobj;
        zval *tmp_member = NULL;
        zval **variable_ptr;
        zend_property_info *property_info;
        
        //define Z_OBJ_P(zval_p) 
        // ((zend_object*)(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zval_p)].bucket.obj.object))
        zobj = Z_OBJ_P(object);
     
        property_info = zend_get_property_info_quick(zobj->ce, member, (zobj->ce->__set != NULL), key TSRMLS_CC);
    
    //执行完$a=new a()后,类a中的成员变量就已经复制到对象中的properties_table中去了,当对象动态增加成员变量时,会放到对象中的properties_table中去
    if (EXPECTED(property_info != NULL) && ((EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) && property_info->offset >= 0) ? (zobj->properties ? ((variable_ptr = (zval**)zobj->properties_table[property_info->offset]) != NULL) : (*(variable_ptr = &zobj->properties_table[property_info->offset]) != NULL)) : (EXPECTED(zobj->properties != NULL) && EXPECTED(zend_hash_quick_find(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, (void **) &variable_ptr) == SUCCESS)))) { /* if we already have this value there, we don't actually need to do anything */ if (EXPECTED(*variable_ptr != value)) { /* if we are assigning reference, we shouldn't move it, but instead assign variable to the same pointer */ if (PZVAL_IS_REF(*variable_ptr)) { zval garbage = **variable_ptr; /* old value should be destroyed */ /* To check: can't *variable_ptr be some system variable like error_zval here? */ Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value); (*variable_ptr)->value = value->value; if (Z_REFCOUNT_P(value) > 0) { zval_copy_ctor(*variable_ptr); } else { efree(value); } zval_dtor(&garbage); } else { zval *garbage = *variable_ptr; /* if we assign referenced variable, we should separate it */ Z_ADDREF_P(value); if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } *variable_ptr = value; zval_ptr_dtor(&garbage); } } } }

     

     

    2.$a->getName()对应的BNF范式

    variable:
            base_variable_with_function_calls T_OBJECT_OPERATOR {  }
                object_property {  } method_or_not variable_properties
                { }
    ;
    
    object_property:
            variable_without_objects {  } { znode tmp_znode;  zend_do_pop_object(&tmp_znode TSRMLS_CC);  zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);}
    ;
    
    method_or_not:
            method                        { $$ = $1; $$.EA = ZEND_PARSED_METHOD_CALL;  }
        |    /* empty */ { $$.EA = ZEND_PARSED_MEMBER; }
    ;
    method:
            { zend_do_begin_method_call(&$$ TSRMLS_CC); }
            function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 1, 1 TSRMLS_CC);  }
    ;
    
    function_call_parameter_list:
            '(' ')'    { Z_LVAL($$.u.constant) = 0; }
        |    '(' non_empty_function_call_parameter_list ')'    { $$ = $2; }
    ;

     

     

     

    3.执行 

    void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
    {
        zend_op *last_op;
        last_op->opcode = ZEND_INIT_METHOD_CALL;
        last_op->result_type = IS_UNUSED;
        last_op->result.num = CG(context).nested_calls;
    }
    
    void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */
    {
        zend_op *opline;
        zend_function_call_entry *fcall;
        zend_stack_top(&CG(function_call_stack), (void **) &fcall);
    
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
            
        opline->opcode = ZEND_DO_FCALL_BY_NAME;
        SET_UNUSED(opline->op1);
        SET_UNUSED(opline->op2);
    }
    static int ZEND_FASTCALL  ZEND_INIT_METHOD_CALL_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        zval *function_name;
        char *function_name_strval;
        int function_name_strlen;
    
        call_slot *call = EX(call_slots) + opline->result.num;
    
        function_name = opline->op2.zv;
    
        function_name_strval = Z_STRVAL_P(function_name);
        function_name_strlen = Z_STRLEN_P(function_name);
    
        call->object = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
    
        /* First, locate the function. */
        call->fbc = Z_OBJ_HT_P(call->object)->get_method(&call->object, function_name_strval, function_name_strlen, ((IS_CONST == IS_CONST) ? (opline->op2.literal + 1) : NULL) TSRMLS_CC);
        
        EX(call) = call;
        ZEND_VM_NEXT_OPCODE();
    }
    
    #define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data TSRMLS_DC

    static int ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { EX(function_state).function = EX(call)->fbc; return zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE zend_bool should_change_scope = 0; zend_function *fbc = EX(function_state).function; zend_uint num_args; EX(object) = EX(call)->object; // 重要 if (fbc->type == ZEND_USER_FUNCTION || fbc->common.scope) { should_change_scope = 1; EX(current_this) = EG(This); EX(current_scope) = EG(scope); EX(current_called_scope) = EG(called_scope); EG(This) = EX(object); //重要 EG(scope) = (fbc->type == ZEND_USER_FUNCTION || !EX(object)) ? fbc->common.scope : NULL; EG(called_scope) = EX(call)->called_scope; } if (fbc->type == ZEND_USER_FUNCTION) { EG(active_symbol_table) = NULL; EG(active_op_array) = &fbc->op_array; EG(return_value_ptr_ptr) = NULL; if (EXPECTED(zend_execute_ex == execute_ex)) { if (EXPECTED(EG(exception) == NULL)) { ZEND_VM_ENTER(); } } } }

     

  • 相关阅读:
    自定义文书思路
    传输
    Netty的组件和设计
    第一款Netty应用程序
    Netty异步和事件驱动
    初识MQTT
    TCP/IP协议分层模型
    uni原生插件的开发(安卓)
    uniapp离线打包记录
    日常问题处理:Linux通过设备名称如何查看硬盘SN
  • 原文地址:https://www.cnblogs.com/taek/p/4296766.html
Copyright © 2020-2023  润新知