zend_class_entry

typedef struct _zend_class_entry zend_class_entry;

struct _zend_class_entry {
char type;
char *name;
zend_uint name_length;
struct _zend_class_entry *parent;
int refcount;
zend_bool constants_updated;
zend_uint ce_flags; HashTable function_table;
HashTable default_properties;
HashTable properties_info;
HashTable default_static_members;
HashTable *static_members;
HashTable constants_table;
const struct _zend_function_entry *builtin_functions; union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
union _zend_function *__callstatic;
union _zend_function *__tostring;
union _zend_function *serialize_func;
union _zend_function *unserialize_func; zend_class_iterator_funcs iterator_funcs; /* handlers */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
union _zend_function *(*get_static_method)(zend_class_entry *ce, char* method, int method_len TSRMLS_DC); /* serializer callbacks */
int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
int (*unserialize)(zval **object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC); zend_class_entry **interfaces;
zend_uint num_interfaces; char *filename;
zend_uint line_start;
zend_uint line_end;
char *doc_comment;
zend_uint doc_comment_len; struct _zend_module_entry *module;
};

typedef struct _zend_property_info {
zend_uint flags;
char *name;
int name_length;
ulong h;
char *doc_comment;
int doc_comment_len;
zend_class_entry *ce;
} zend_property_info;

1.BNF范式(语法规则)

%token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)"
%token T_EXTENDS    "extends (T_EXTENDS)"
unticked_class_declaration_statement:
class_entry_type T_STRING extends_from
{ zend_do_begin_class_declaration(&$, &$, &$ TSRMLS_CC); }
implements_list
'{'
class_statement_list
'}' { zend_do_end_class_declaration(&$, &$ TSRMLS_CC); }
| interface_entry T_STRING
{ zend_do_begin_class_declaration(&$, &$, NULL TSRMLS_CC); }
interface_extends_list
'{'
class_statement_list
'}' { zend_do_end_class_declaration(&$, NULL TSRMLS_CC); }
;

//类的修饰符

class_entry_type:
        T_CLASS            { $$.u.op.opline_num = CG(zend_lineno); $$.EA = 0; }

|    T_ABSTRACT T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }

|    T_TRAIT { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_TRAIT; }

|    T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; }

;

extends_from:

        /* empty */                    { $$.op_type = IS_UNUSED; }

|    T_EXTENDS fully_qualified_class_name    { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); }

;

class_statement_list:
class_statement_list class_statement
| /* empty */
; class_statement:
variable_modifiers { CG(access_type) = Z_LVAL($.u.constant); } class_variable_declaration ';' //定义成员变量
| class_constant_declaration ';'
| trait_use_statement
| method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$, &$, , $.op_type, &$ TSRMLS_CC); } '('
parameter_list ')' method_body { zend_do_abstract_method(&$, &$, &$ TSRMLS_CC); zend_do_end_function_declaration(&$ TSRMLS_CC); } //定义成员方法
; variable_modifiers:
non_empty_member_modifiers { $$ = $; }
| T_VAR { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
  ;
method_modifiers:
/* empty */ { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
| non_empty_member_modifiers { $$ = $; if (!(Z_LVAL($$.u.constant) & ZEND_ACC_PPP_MASK)) { Z_LVAL($$.u.constant) |= ZEND_ACC_PUBLIC; } }
;

non_empty_member_modifiers:
  member_modifier { $$ = $1; }

  | non_empty_member_modifiers member_modifier { Z_LVAL($$.u.constant) = zend_do_verify_access_types(&$1, &$2); }

;

member_modifier: //成员修饰符,用于成员变量以及成员方法
   T_PUBLIC { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }

  | T_PROTECTED { Z_LVAL($$.u.constant) = ZEND_ACC_PROTECTED; }

  | T_PRIVATE { Z_LVAL($$.u.constant) = ZEND_ACC_PRIVATE; }

  | T_STATIC { Z_LVAL($$.u.constant) = ZEND_ACC_STATIC; }

  | T_ABSTRACT { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }

  | T_FINAL { Z_LVAL($$.u.constant) = ZEND_ACC_FINAL; }

;


method_body: //方法体
';' /* abstract method */        { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
| '{' inner_statement_list '}' { Z_LVAL($$.u.constant) = ; }
; inner_statement_list:
inner_statement_list { zend_do_extended_info(TSRMLS_C); } inner_statement { HANDLE_INTERACTIVE(); }
| /* empty */
; inner_statement: //具体的函数体 statement
| function_declaration_statement
| class_declaration_statement
| T_HALT_COMPILER '(' ')' ';' { zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope"); }
;


//类名::$静态成员变量名字
static_member:
class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $; zend_do_fetch_static_member(&$$, &$ TSRMLS_CC); }
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $; zend_do_fetch_static_member(&$$, &$ TSRMLS_CC); } ;

  variable_without_objects:
      reference_variable { $$ = $1; }
    | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); }
  ;

  reference_variable:
      reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
    | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); }
    | compound_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
  ;

  compound_variable:
      T_VARIABLE { $$ = $1; }
    | '$' '{' expr '}' { $$ = $3; }
  ;


class_variable_declaration
:
class_variable_declaration ',' T_VARIABLE { zend_do_declare_property(&$, NULL, CG(access_type) TSRMLS_CC); }
| class_variable_declaration ',' T_VARIABLE '=' static_scalar { zend_do_declare_property(&$, &$, CG(access_type) TSRMLS_CC); }
| T_VARIABLE { zend_do_declare_property(&$, NULL, CG(access_type) TSRMLS_CC); }
| T_VARIABLE '=' static_scalar { zend_do_declare_property(&$, &$, CG(access_type) TSRMLS_CC); }
; static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $; }
| namespace_name { zend_do_fetch_constant(&$$, NULL, &$, ZEND_CT, TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$ TSRMLS_CC); $ = $$; zend_do_fetch_constant(&$$, NULL, &$, ZEND_CT, TSRMLS_CC); }
| T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($.u.constant), Z_STRLEN($.u.constant)+); memcpy(&(tmp[]), Z_STRVAL($.u.constant), Z_STRLEN($.u.constant)+); tmp[] = '\\'; efree(Z_STRVAL($.u.constant)); Z_STRVAL($.u.constant) = tmp; ++Z_STRLEN($.u.constant); zend_do_fetch_constant(&$$, NULL, &$, ZEND_CT, TSRMLS_CC); }
| '+' static_scalar { ZVAL_LONG(&$.u.constant, ); add_function(&$.u.constant, &$.u.constant, &$.u.constant TSRMLS_CC); $$ = $; }
| '-' static_scalar { ZVAL_LONG(&$.u.constant, ); sub_function(&$.u.constant, &$.u.constant, &$.u.constant TSRMLS_CC); $$ = $; }
| T_ARRAY '(' static_array_pair_list ')' { $$ = $; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; }
| '[' static_array_pair_list ']' { $$ = $; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; }
| static_class_constant { $$ = $; }
| T_CLASS_C { $$ = $; }
; common_scalar:
T_LNUMBER { $$ = $; }
| T_DNUMBER { $$ = $; }
| T_CONSTANT_ENCAPSED_STRING { $$ = $; }
| T_LINE { $$ = $; }
| T_FILE { $$ = $; }
| T_DIR { $$ = $; }
| T_TRAIT_C { $$ = $; }
| T_METHOD_C { $$ = $; }
| T_FUNC_C { $$ = $; }
| T_NS_C { $$ = $; }
| T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$ = $; CG(heredoc) = Z_STRVAL($.u.constant); CG(heredoc_len) = Z_STRLEN($.u.constant); }
| T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); INIT_PZVAL(&$$.u.constant); $$.op_type = IS_CONST; CG(heredoc) = Z_STRVAL($.u.constant); CG(heredoc_len) = Z_STRLEN($.u.constant); }
;

 开始声明类

void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */
{
zend_op *opline;
int doing_inheritance = ;
zend_class_entry *new_class_entry;
char *lcname;
int error = ;
zval **ns_name, key; if (CG(active_class_entry)) {
zend_error(E_COMPILE_ERROR, "Class declarations may not be nested");
return;
}
//类名转换为小写
lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
//类名不能是 self ,parent关键字
if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) {
efree(lcname);
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant));
} /* Class name must not conflict with import names */
if (CG(current_import) &&
zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+, (void**)&ns_name) == SUCCESS) {
error = ;
} if (CG(current_namespace)) {
/* Prefix class name with name of current namespace */
znode tmp; tmp.op_type = IS_CONST;
tmp.u.constant = *CG(current_namespace);
zval_copy_ctor(&tmp.u.constant);
zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
*class_name = tmp;
efree(lcname);
lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
} if (error) {
char *tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name)); if (Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||
memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {
zend_error(E_COMPILE_ERROR, "Cannot declare class %s because the name is already in use", Z_STRVAL(class_name->u.constant));
}
efree(tmp);
}
//为zend_class_entry分配内存,并设置属性
new_class_entry = emalloc(sizeof(zend_class_entry));
new_class_entry->type = ZEND_USER_CLASS; //用户自定义的类
new_class_entry->name = zend_new_interned_string(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + , TSRMLS_CC);
new_class_entry->name_length = Z_STRLEN(class_name->u.constant); zend_initialize_class_data(new_class_entry, TSRMLS_CC);
new_class_entry->info.user.filename = zend_get_compiled_filename(TSRMLS_C);
new_class_entry->info.user.line_start = class_token->u.op.opline_num;
new_class_entry->ce_flags |= class_token->EA; if (parent_class_name && parent_class_name->op_type != IS_UNUSED) {
switch (parent_class_name->EA) {
case ZEND_FETCH_CLASS_SELF:
zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved");
break;
case ZEND_FETCH_CLASS_PARENT:
zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved");
break;
case ZEND_FETCH_CLASS_STATIC:
zend_error(E_COMPILE_ERROR, "Cannot use 'static' as class name as it is reserved");
break;
default:
break;
}
doing_inheritance = ;
} opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->op1_type = IS_CONST;
build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);
opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); opline->op2_type = IS_CONST; if (doing_inheritance) {
/* Make sure a trait does not try to extend a class */
if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name);
} opline->extended_value = parent_class_name->u.op.var;
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
} else {
//设置opcode
opline->opcode = ZEND_DECLARE_CLASS;
} LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, );
CALCULATE_LITERAL_HASH(opline->op2.constant);

//先add/update到CG(class_table)中,现在是编译阶段,如果这里不把zend_class_entry存储到CG(class_table)里的话,在执行时,是找不到的zend_class_entry这个的,
zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(
&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry; opline->result.var = get_temporary_variable(CG(active_op_array));
opline->result_type = IS_VAR;
GET_NODE(&CG(implementing_class), opline->result); if (CG(doc_comment)) {
CG(active_class_entry)->info.user.doc_comment = CG(doc_comment);
CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len);
CG(doc_comment) = NULL;
CG(doc_comment_len) = ;
}
}

执行opcode ZEND_DECLARE

static int ZEND_FASTCALL  ZEND_DECLARE_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE SAVE_OPLINE();
EX_T(opline->result.var).class_entry = do_bind_class(EX(op_array), opline, EG(class_table), TSRMLS_CC);
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
} ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
{
zend_class_entry *ce, **pce;
zval *op1, *op2; if (compile_time) {
op1 = &CONSTANT_EX(op_array, opline->op1.constant);
op2 = &CONSTANT_EX(op_array, opline->op2.constant);
} else {
op1 = opline->op1.zv;
op2 = opline->op2.zv;
}
if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) {
zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
return NULL;
} else {
ce = *pce;
}
ce->refcount++;
if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
ce->refcount--;
if (!compile_time) {
/* If we're in compile time, in practice, it's quite possible
* that we'll never reach this class declaration at runtime,
* so we shut up about it. This allows the if (!defined('FOO')) { return; }
* approach to work.
*/
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name);
}
return NULL;
} else {
if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
zend_verify_abstract_class(ce TSRMLS_CC);
}
return ce;
}
}

2.定义变量的编译

void zend_do_declare_property(const znode *var_name, const znode *value, zend_uint access_type TSRMLS_DC) /* {{{ */
{
zval *property;
zend_property_info *existing_property_info;
char *comment = NULL;
int comment_len = ;

   //接口不能包含变量
if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables");
}
   //属性不能定义为抽象
if (access_type & ZEND_ACC_ABSTRACT) {
zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract");
}
   //变量前面的修饰符不能为final
if (access_type & ZEND_ACC_FINAL) {
zend_error(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, the final modifier is allowed only for methods and classes",
CG(active_class_entry)->name, var_name->u.constant.value.str.val);
}
  
//不能多次定义同一变量
if (zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+, (void **) &existing_property_info)==SUCCESS) {
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
}
ALLOC_ZVAL(property); if (value) {
*property = value->u.constant;
} else {
INIT_PZVAL(property);
Z_TYPE_P(property) = IS_NULL;
} if (CG(doc_comment)) {
comment = CG(doc_comment);
comment_len = CG(doc_comment_len);
CG(doc_comment) = NULL;
CG(doc_comment_len) = ;
} zend_declare_property_ex(CG(active_class_entry), zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + , TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC);
efree(var_name->u.constant.value.str.val);
}
ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, const char *doc_comment, int doc_comment_len TSRMLS_DC) /* {{{ */
{
zend_property_info property_info, *property_info_ptr;
const char *interned_name;
ulong h = zend_get_hash_value(name, name_length+); if (!(access_type & ZEND_ACC_PPP_MASK)) {
access_type |= ZEND_ACC_PUBLIC;
}
if (access_type & ZEND_ACC_STATIC) {
//修饰符为static的,例如 public static $xxx
if (zend_hash_quick_find(&ce->properties_info, name, name_length + , h, (void**)&property_info_ptr) == SUCCESS &&
(property_info_ptr->flags & ZEND_ACC_STATIC) != ) {
property_info.offset = property_info_ptr->offset;
zval_ptr_dtor(&ce->default_static_members_table[property_info.offset]);
zend_hash_quick_del(&ce->properties_info, name, name_length + , h);
} else {
property_info.offset = ce->default_static_members_count++;
ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
}
ce->default_static_members_table[property_info.offset] = property;
if (ce->type == ZEND_USER_CLASS) {
ce->static_members_table = ce->default_static_members_table;
}
} else {
//这里应该是public $xxx这样的变量
if (zend_hash_quick_find(&ce->properties_info, name, name_length + , h, (void**)&property_info_ptr) == SUCCESS &&
(property_info_ptr->flags & ZEND_ACC_STATIC) == ) {
property_info.offset = property_info_ptr->offset;
zval_ptr_dtor(&ce->default_properties_table[property_info.offset]);
zend_hash_quick_del(&ce->properties_info, name, name_length + , h);
} else {
property_info.offset = ce->default_properties_count++;
ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
}
ce->default_properties_table[property_info.offset] = property;
}
if (ce->type & ZEND_INTERNAL_CLASS) {
switch(Z_TYPE_P(property)) {
case IS_ARRAY:
case IS_CONSTANT_ARRAY:
case IS_OBJECT:
case IS_RESOURCE:
zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
break;
default:
break;
}
}
switch (access_type & ZEND_ACC_PPP_MASK) {
case ZEND_ACC_PRIVATE: {
char *priv_name;
int priv_name_length; zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
property_info.name = priv_name;
property_info.name_length = priv_name_length;
}
break;
case ZEND_ACC_PROTECTED: {
char *prot_name;
int prot_name_length; zend_mangle_property_name(&prot_name, &prot_name_length, "*", , name, name_length, ce->type & ZEND_INTERNAL_CLASS);
property_info.name = prot_name;
property_info.name_length = prot_name_length;
}
break;
case ZEND_ACC_PUBLIC:
if (IS_INTERNED(name)) {
property_info.name = (char*)name;
} else {
property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length);
}
property_info.name_length = name_length;
break;
} interned_name = zend_new_interned_string(property_info.name, property_info.name_length+, TSRMLS_CC);
if (interned_name != property_info.name) {
if (ce->type == ZEND_USER_CLASS) {
efree((char*)property_info.name);
} else {
free((char*)property_info.name);
}
property_info.name = interned_name;
} property_info.flags = access_type; //相应的修饰符
property_info.h = (access_type & ZEND_ACC_PUBLIC) ? h : zend_get_hash_value(property_info.name, property_info.name_length+); property_info.doc_comment = doc_comment;
property_info.doc_comment_len = doc_comment_len; property_info.ce = ce; //属于哪个类 zend_hash_quick_update(&ce->properties_info, name, name_length+, h, &property_info, sizeof(zend_property_info), NULL); return SUCCESS;
}

类名::$静态成员名字

void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
{
znode class_node;
zend_llist *fetch_list_ptr;
zend_llist_element *le;
zend_op *opline_ptr;
zend_op opline; if (class_name->op_type == IS_CONST &&
ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, TSRMLS_CC);
class_node = *class_name;
} else {
zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
}
zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
if (result->op_type == IS_CV) {
init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_W;
opline.result_type = IS_VAR;
opline.result.var = get_temporary_variable(CG(active_op_array));
opline.op1_type = IS_CONST;      //将result的name存储到CG(active_op_array)中的literal数组中,返回key给opline.op1.constant
LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, );
CALCULATE_LITERAL_HASH(opline.op1.constant);
GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
if (class_node.op_type == IS_CONST) {
opline.op2_type = IS_CONST; //将class_node里面的zval值 存储在CG(active_op_array)中的literal数组中,返回key给opline.op2.costant
opline.op2.constant =
zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
} else {
SET_NODE(opline.op2, &class_node);
}
GET_NODE(result,opline.result);
opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
opline_ptr = &opline; zend_llist_add_element(fetch_list_ptr, &opline);
} else {
le = fetch_list_ptr->head; opline_ptr = (zend_op *)le->data;
if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) {
init_op(&opline TSRMLS_CC);
opline.opcode = ZEND_FETCH_W;
opline.result_type = IS_VAR;
opline.result.var = get_temporary_variable(CG(active_op_array));
opline.op1_type = IS_CONST;
LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, );
CALCULATE_LITERAL_HASH(opline.op1.constant);
GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
if (class_node.op_type == IS_CONST) {
opline.op2_type = IS_CONST;
opline.op2.constant =
zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
} else {
SET_NODE(opline.op2, &class_node);
}
opline.extended_value |= ZEND_FETCH_STATIC_MEMBER;
COPY_NODE(opline_ptr->op1, opline.result); zend_llist_prepend_element(fetch_list_ptr, &opline);
} else {
if (opline_ptr->op1_type == IS_CONST) {
GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant);
}
if (class_node.op_type == IS_CONST) {
opline_ptr->op2_type = IS_CONST;
opline_ptr->op2.constant =
zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC);
} else {
SET_NODE(opline_ptr->op2, &class_node);
}
opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER;
}
}
}
static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_CONST(int type, ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
zval *varname;
zval **retval;
zval tmp_varname;
HashTable *target_symbol_table;
ulong hash_value; SAVE_OPLINE();
varname = opline->op1.zv; if (IS_CONST != IS_UNUSED) {
zend_class_entry *ce; if (IS_CONST == IS_CONST) {
if (CACHED_PTR(opline->op2.literal->cache_slot)) {
ce = CACHED_PTR(opline->op2.literal->cache_slot); //从cache中取出类
} else {
ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + , TSRMLS_CC);
if (UNEXPECTED(ce == NULL)) {
if (IS_CONST != IS_CONST && varname == &tmp_varname) {
zval_dtor(&tmp_varname);
} CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
CACHE_PTR(opline->op2.literal->cache_slot, ce); //将类放入cache中
}
} else {
ce = EX_T(opline->op2.var).class_entry;
}
retval = zend_std_get_static_property(ce, Z_STRVAL_P(varname), Z_STRLEN_P(varname), , ((IS_CONST == IS_CONST) ? opline->op1.literal : NULL) TSRMLS_CC); } else {
//代码省略
}

#define CACHED_PTR(num) \
  EG(active_op_array)->run_time_cache[(num)]


#define CACHE_PTR(num, ptr) do { \
  EG(active_op_array)->run_time_cache[(num)] = (ptr); \
 } while (0)


zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC) /* {{{ */
{
zend_class_entry **pce;
int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == ; if (zend_lookup_class_ex(class_name, class_name_len, key, use_autoload, &pce TSRMLS_CC) == FAILURE) {
if (use_autoload) {
if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == && !EG(exception)) {
if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
zend_error(E_ERROR, "Interface '%s' not found", class_name);
} else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
zend_error(E_ERROR, "Trait '%s' not found", class_name);
} else {
zend_error(E_ERROR, "Class '%s' not found", class_name);
}
}
}
return NULL;
}
return *pce;
}
ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */
{
zval **args[];
zval autoload_function;
zval *class_name_ptr;
zval *retval_ptr = NULL;
int retval, lc_length;
char *lc_name;
char *lc_free;
zend_fcall_info fcall_info;
zend_fcall_info_cache fcall_cache;
char dummy = ;
ulong hash;
ALLOCA_FLAG(use_heap) if (key) {
lc_name = Z_STRVAL(key->constant);
lc_length = Z_STRLEN(key->constant) + ;
hash = key->hash_value;
} else {
if (name == NULL || !name_length) {
return FAILURE;
} lc_free = lc_name = do_alloca(name_length + , use_heap);
zend_str_tolower_copy(lc_name, name, name_length);
lc_length = name_length + ; if (lc_name[] == '\\') {
lc_name += ;
lc_length -= ;
} hash = zend_inline_hash_func(lc_name, lc_length);
} if (zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) {
if (!key) {
free_alloca(lc_free, use_heap);
}
return SUCCESS;
}


ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, zend_bool silent, const zend_literal *key TSRMLS_DC) /* {{{ */
{
zend_property_info *property_info;
ulong hash_value; if (UNEXPECTED(!key) ||
(property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) == NULL) { //如果cache中没有,那么从ce->properties_info中查找
if (EXPECTED(key != NULL)) {
hash_value = key->hash_value;
} else {
hash_value = zend_hash_func(property_name, property_name_len+);
} if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+, hash_value, (void **) &property_info)==FAILURE)) {
if (!silent) {
zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
}
return NULL;
} #if DEBUG_OBJECT_HANDLERS
zend_printf("Access type for %s::%s is %s\n", ce->name, property_name, zend_visibility_string(property_info->flags));
#endif if (UNEXPECTED(!zend_verify_property_access(property_info, ce TSRMLS_CC))) {
if (!silent) {
zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
}
return NULL;
} if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == )) {
if (!silent) {
zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
}
return NULL;
} zend_update_class_constants(ce TSRMLS_CC); //不知道为什么这里update? if (EXPECTED(key != NULL)) {
CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info); //放入cache中
}
} return &CE_STATIC_MEMBERS(ce)[property_info->offset];
} //检查成员变量的权限

static zend_always_inline int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */
{
  switch (property_info->flags & ZEND_ACC_PPP_MASK) {
  case ZEND_ACC_PUBLIC:
    return 1;
  case ZEND_ACC_PROTECTED:
    return zend_check_protected(property_info->ce, EG(scope));
  case ZEND_ACC_PRIVATE:
    if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) {
      return 1;
    } else {
      return 0;
    }
    break;
  }
  return 0;
}

 

#define CACHED_POLYMORPHIC_PTR(num, ce) \
  ((EG(active_op_array)->run_time_cache[(num)] == (ce)) ? \
  EG(active_op_array)->run_time_cache[(num) + 1] : \
  NULL)


#define CACHE_POLYMORPHIC_PTR(num, ce, ptr) do { \
  EG(active_op_array)->run_time_cache[(num)] = (ce); \
  EG(active_op_array)->run_time_cache[(num) + 1] = (ptr); \
} while (0)

define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table)


php类的实现的更多相关文章

  1. Java类的继承与多态特性-入门笔记

    相信对于继承和多态的概念性我就不在怎么解释啦!不管你是.Net还是Java面向对象编程都是比不缺少一堂课~~Net如此Java亦也有同样的思想成分包含其中. 继承,多态,封装是Java面向对象的3大特 ...

  2. C++ 可配置的类工厂

    项目中常用到工厂模式,工厂模式可以把创建对象的具体细节封装到Create函数中,减少重复代码,增强可读和可维护性.传统的工厂实现如下: class Widget { public: virtual i ...

  3. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  4. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第二章:利用模型类创建视图、控制器和数据库

    在这一章中,我们将直接进入项目,并且为产品和分类添加一些基本的模型类.我们将在Entity Framework的代码优先模式下,利用这些模型类创建一个数据库.我们还将学习如何在代码中创建数据库上下文类 ...

  5. ASP.NET Core 折腾笔记二:自己写个完整的Cache缓存类来支持.NET Core

    背景: 1:.NET Core 已经没System.Web,也木有了HttpRuntime.Cache,因此,该空间下Cache也木有了. 2:.NET Core 有新的Memory Cache提供, ...

  6. .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类

    .NET Core中间件的注册和管道的构建(2)---- 用UseMiddleware扩展方法注册中间件类 0x00 为什么要引入扩展方法 有的中间件功能比较简单,有的则比较复杂,并且依赖其它组件.除 ...

  7. Java基础Map接口+Collections工具类

    1.Map中我们主要讲两个接口 HashMap  与   LinkedHashMap (1)其中LinkedHashMap是有序的  怎么存怎么取出来 我们讲一下Map的增删改查功能: /* * Ma ...

  8. PHP-解析验证码类--学习笔记

    1.开始 在 网上看到使用PHP写的ValidateCode生成验证码码类,感觉不错,特拿来分析学习一下. 2.类图 3.验证码类部分代码 3.1  定义变量 //随机因子 private $char ...

  9. C# 多种方式发送邮件(附帮助类)

    因项目业务需要,需要做一个发送邮件功能,查了下资料,整了整,汇总如下,亲测可用- QQ邮箱发送邮件 #region 发送邮箱 try { MailMessage mail = new MailMess ...

  10. .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator

    去年,我在一篇文章用原始方法解析复杂字符串,json一定要用JsonMapper么?中介绍了简单的JSON解析的问题,那种方法在当时的环境是非常方便的,因为不需要生成实体类,结构很容易解析.但随着业务 ...

随机推荐

  1. @+id/和android:id的区别

    android:id="@+id/btn",表示在R.java文件里面新增一个id为btn的控件索引,最常用的一种声明控件id的方式.android:id="@andro ...

  2. const和#define的区别

    在刷题的时候经常遇到定义全局常量我一般都是用#define(可能是因为很少接触const的原因) 在昨天做到51nod1082时照常暴力用#define定义最大.可是提交超时..... 后来看他人写的 ...

  3. php代码加密|PHP源码加密——实现方法

    Encipher - PHP代码加密 | PHP源码加密下载地址:https://github.com/uniqid/encipher 该加密程序是用PHP代码写的,加密后代码无需任何附加扩展,无需安 ...

  4. Spark Tungsten揭秘 Day1 jvm下的性能优化

    Spark Tungsten揭秘 Day1 jvm下的性能优化 今天开始谈下Tungsten,首先我们需要了解下其背后是符合了什么样的规律. jvm对分布式天生支持 整个Spark分布式系统是建立在分 ...

  5. Oracle非默认监听的处理会遇到的问题以及处理方法

    第一种情况:只是修改默认端口 1.当前监听状态: C:\Windows\system32>lsnrctl status LSNRCTL for 64-bit Windows: Version 1 ...

  6. flash memory

    数据删除不是以单个的字节为单位而是以固定的区块为单位(注意:NOR Flash 为字节存储.),区块大小一般为256KB到20MB. 由于其断电时仍能保存数据,闪存通常被用来保存设置信息,如在电脑的B ...

  7. WPF中的多点触摸事件

    UIElement在WPF4下添加了很多支持多点触摸的事件,通过它们可以在硬件支持的情况下处理多点触摸,以下通过代码来说明通过处理这些事件,我们可以做些什么: 一.触摸相关的多种事件,跟鼠标事件是对应 ...

  8. 如何将无线路由器作为交换机,将光猫(路由器A)分出来的一条网线接到自家另一台路由器B上,最大化利用网络资源

    从隔壁邻居只接了一条网线过来,由于无线网络的距离有限,不能覆盖到家里任何角落,然而,我又想家里一台台式电脑和无线设备都能够连接wifi进行上网。 摸索了一个上午,知道将家里的无线路由器B当作一个无线A ...

  9. WPF系列

    一.ListView绑定数据源XML //前端代码 1 <Window x:Class="ListView读取XML数据.MainWindow" xmlns="ht ...

  10. IOS成长之路-调用照相机和相册功能(转)

    转载自:http://blog.csdn.net/like7xiaoben/article/details/8465237 //先设定sourceType为相机,然后判断相机是否可用(ipod)没相机 ...