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

 

原文地址:https://www.cnblogs.com/taek/p/4296766.html