<?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(&$); zend_do_assign(&$$, &$, &$ TSRMLS_CC); }
;
variable:
base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$ TSRMLS_CC); }
object_property { zend_do_push_object(&$ TSRMLS_CC); } method_or_not variable_properties
{ zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $.EA | ($.EA ? $.EA : $.EA); }
;
base_variable_with_function_calls:
compound_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$, TSRMLS_CC); }
;
compound_variable:
T_VARIABLE { $$ = $; }
;
object_property:
object_dim_list { $$ = $; }
;
object_dim_list:
variable_name { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$ TSRMLS_CC);}
;
variable_name:
T_STRING { $$ = $; }

理解版

expr_without_variable:
variable '=' expr { zend_check_writable_variable(&$); zend_do_assign(&$$, &$, &$ TSRMLS_CC); }
;
variable:
base_variable T_OBJECT_OPERATOR object_property method_or_not variable_properties ;
base_variable:
T_VARIABLE { fetch_simple_variable(&$$, &$, TSRMLS_CC); }
; object_property:
T_STRING { zend_do_fetch_property(&$$, &tmp_znode, &$ 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")-) &&
!memcmp(Z_STRVAL(varname->u.constant), "this", sizeof("this") - )) &&
(CG(active_op_array)->last == ||
CG(active_op_array)->opcodes[CG(active_op_array)->last-].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 = ;
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 == ) {
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-];
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+)->op1_type, &(opline+)->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) == ) &&
property_info->offset >= ) ?
(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+, 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) > ) {
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, &$ TSRMLS_CC);}
; method_or_not:
method { $$ = $; $$.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(&$, &$$, , TSRMLS_CC); }
; function_call_parameter_list:
'(' ')' { Z_LVAL($$.u.constant) = ; }
| '(' non_empty_function_call_parameter_list ')' { $$ = $; }
;

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

php 类 成员变量 $this->name='abc'的更多相关文章

  1. static 类成员变量 和 static const类成员变量

    1.使用static类的优点: (1)避免与其他类的成员或者全局变量冲突 (2)可以封装 (3)阅读性好 2.static 数据成员独立于该类的任意对象而存在 static数据成员的类型可以是该成员所 ...

  2. Qt一个project调用还有一个project的类成员变量

    一句两句话已经不能表达如今的激动情绪了.唯有感叹知识的博大精深,并把感叹转变为文字. 同一个project调用其它类成员变量很easy. 如: 定义 Test1.h中申明成员变量 class A { ...

  3. static-const 类成员变量

    [本文链接] http://www.cnblogs.com/hellogiser/p/static-const.html [分析] const数据成员必须在构造函数初始化列表中初始化; static数 ...

  4. [UE4]C++的const类成员函数

    我们知道,在C++中,若一个变量声明为const类型,则试图修改该变量的值的操作都被视编译错误.例如: const char blank = ‘’; blank = ‘\n’; // 错误 要声明一个 ...

  5. C# 利用反射动态调用类成员

    用反射动态调用类成员,需要Type类的一个方法:InvokeMember.对该方法的声明如下(摘抄于MSDN): publicobject InvokeMember(    string name, ...

  6. 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)

    在C++中,成员函数的指针是个比较特殊的东西.对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用.但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法. ...

  7. C++ 面向对象 类成员函数this指针

    每个类成员函数都只涉及一个对象, 即调用它的对象. 但有时候方法可能涉及到两个对象, 在这种情况下需要使用C++ 的 this 指针 假设将方法命名为topval(), 则函数调用stock1.top ...

  8. C++类成员空间分配和虚函数表

    最近在自学python,看到继承和类,就顺便复习了C++的类和继承等方面的知识. 先看Base基类 class Base { private: virtual void display() { cou ...

  9. 面向对象:三大特性、类成员、property

    一.类的基础知识 python 一切皆为对象. 我们以前的str,list,int 都是对象. 1.1 类的定义 与 调用 class 关键字用来定义类,注意类名首字母大写. 类的调用,先实例化一个类 ...

  10. QT创建与调用Dll方法(包括类成员)--显式调用

    看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...

随机推荐

  1. C语言中的七种排序算法

    堆排序: void HeapAdjust(int *arraydata,int rootnode,int len) { int j; int t; *rootnode+<len) { j=*ro ...

  2. Failed to execute command: ""C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\ResGen.exe" 的一个解决办法

    最近在做wpf项目,期间下了一些源码参考,但是在build时经常遇到下面这种bug: Error 2 Failed to execute command: ""C:\Program ...

  3. RedHat6.4 用UDEV配置ASM所需磁盘

    同事在装一套RAC测试环境,结果发现原来用ASMLIB来配置磁盘,在安装GRID的时候,最终报错了,经过检查发现居然两边的磁盘不匹配.A机的sdb,sdc分别对应OCRVOL1,OCRVOL2,但是B ...

  4. Web 高性能开发汇总

    1. Http服务器: 让Windows Server 2008+IIS 7+ASP.NET支持10万个同时请求 大规模网站架构实战之体系结构(一) 大规模网站架构之WEB加速器SQUID(二) ii ...

  5. vim中编写python代码使用python-mode和syntastic插件时警告(Warning)的消除

    问题: 在Vim使用了syntastic后,编写代码时,可以对代码错误和警告进行相对实时的了解,对编写代码有很大的帮助.同时这个插件和python-mode一起工作时,可以对python代码的编写提供 ...

  6. (转载)Unity3d摄像机Camera参数详解

    1. Clear Flags:清除标记.决定屏幕的哪部分将被清除.一般用户使用对台摄像机来描绘不同游戏对象的情况,有3中模式选择: Skybox:天空盒.默认模式.在屏幕中的空白部分将显示当前摄像机的 ...

  7. 在openwrt上初体验PostgreSQL数据库

    要求 请确保在你的路由器shell 中有以下这些命令 adduser, deluser, addgroup, delgroup, su . 还需要熟悉su,chown ,opkg,mkdir,服务操作 ...

  8. mybatis(1):入坑篇

    依赖 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artif ...

  9. Excel 隐藏功能区命令

    Application.ExecuteExcel4Macro "SHOW.TOOLBAR(""Ribbon"",False)"

  10. POJ1734 - Sightseeing trip

    DescriptionThere is a travel agency in Adelton town on Zanzibar island. It has decided to offer its ...