<?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#】无边框窗体移动的三种方法

    1. 重写WndProc protected override void WndProc(ref Message m) { const int WM_NCHITTEST = 0x84; const i ...

  2. lnmp全面优化集合nginx+mysql+php

    lnmp的全名是linux+nginx+mysql+php,既然是全面优化那我们就从linux系统的选择入手.debian系统可以算是 linux各分支中做的比较突出的一类,连谷歌都抛弃linux订制 ...

  3. javascript与DOM的渊源

    1. JavaScript的起源 1.1 JavaScript的诞生与发展 JavaScript最初由Netscape的Brendan Eich设计, Netscape在最初将其脚本语言命名为Live ...

  4. (转)《深入理解java虚拟机》学习笔记1——Java内存结构

    java虚拟机规范规定的java虚拟机内存其实就是java虚拟机运行时数据区,其架构如下: 其中方法区和堆是由所有线程共享的数据区. Java虚拟机栈,本地方法栈和程序计数器是线程隔离的数据区. (1 ...

  5. 一步步学习NHibernate(9)——连接查询和子查询(1)

    请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...

  6. 【学习总结】整理一下int, NSInteger 等概念

    基本需要知道的 : unsigned : 没符号的 signed  : 有符号的 int : 整型 看看OC的定义 : #if __LP64__ || (TARGET_OS_EMBEDDED & ...

  7. android应用activity中调出输入法后界面调整问题的解决

    在自己写的一个小应用中发现一个问题,当调出输入法后界面最下方的一个按钮被挤到了输入法的上面,这样很不美观,所以找了一下解决办法记录如下: 在AndroidManifest.xml文件中找到对应的act ...

  8. [SQL SERVER系列]之常用函数和开窗函数介绍及实例

    本文主要介绍SQL SERVER数据库中一些常用的系统函数及其SQL SERVER 2005以上支持的开窗函数. 1.常用函数 --从字符串右边截取指定字符数 select RIGHT('HELLO' ...

  9. swift基础--运算符

    (1)加减乘除 (2)三目运算,切记后面的空格如果不加会报错的.估计是苹果的bug. (3)聚合运算符,省却了一个判断,很人性化 (4)区间运算符 //加减乘除等等 let a = 2 let b = ...

  10. PHPCMS搭建wap手机网站

    PHPCMS搭建PC端网站比较方便,但是在wap手机端方面却不怎么实用,而且自带的手机建站感觉不是很好,而且模版不好控制,现在对其进行修改,手机建站个人感觉比较方便 首先在phpcms/libs/fu ...