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. 6个好用的Web开发工具

    在过去的几年间,涌现出了很多Web开发工具,它们大多还是比较吸引人的,方便了我们的工作.我们可以学习一下这些新东西,短时间就可以拓宽思路(PHP100推荐:学习10分钟,改变你的程序员生涯).这些应用 ...

  2. V9自定义分页函数

    大家做网站的时候,可能很多时候分页样式都得根据模板的要求来控制的,这时很多人都会去修改全局文件phpcms\libs\functions \global.func.php里的pages()函数,这样问 ...

  3. 思道OA PK 通达OA 同场竞技 谁与争锋

    技术架构 思道OA 通达OA 开发语言 微软ASP.NET 4.0 PHP开源脚本语言 64位平台 64位 32位 数据库 SQL Server大数据库 MySQL开源数据库 官网下载 下载地址 下载 ...

  4. Linux各发行版本 优缺点 简介

    2008.01.21 13:43 Linux最早由Linus Benedict Torvalds在1991年开始编写.在这之前,RichardStallman创建了Free SoftwareFound ...

  5. KM3

    本科:读完一本书,知道book里讲的是什么,带有知识吸收: 硕士:读完一本书,知道book里的内容,而且还能发现相关的问题,带有知识的思考: 博士:读完一本书,知道book里的内容,而且还能发现相关的 ...

  6. ASP.NET MVC 开发中遇到的两个小问题

    最近在做一个网站,用asp.net MVC4.0来开发,今天遇到了两个小问题,通过查找相关渠道解决了,在这里把这两个问题写出来,问题非常简单,不喜勿喷,mark之希望可以给遇到相同问题的初学者一点帮助 ...

  7. 2016022601 - redis入门了解

    今天开始学习redis,先从网页上学习,主要学习地址是:易百中的redis和redis中国网站. 此片章学习来自于自:http://www.yiibai.com/redis/redis_quick_g ...

  8. 程序使用嵌套的for循环找出2〜100中的素数

    #import <Foundation/Foundation.h> int main () { /* local variable definition */ int i, j; ; i& ...

  9. BitSet

    前几天干了一件比较无聊的事儿——抄了一遍C++ STL bitset的源代码,把不懂的宏定义去掉了,发现(暂时)还能用,嘿嘿. #ifndef BITSET_H #define BITSET_H #i ...

  10. iOS 开发一年总结

    收获很多 1. 一个人包办从构思, 设计, 实现, 推广的全过程, 对自己的能力, 特别是能力范围有很大的提升. 以前在公司上班仅仅局限在实现的局域内, 现在在做自己的产品时, 在设计时的取舍, 对工 ...