這篇要詳細講講PHP類的成員屬性及方法.
上一篇中曾經介紹到zend_do_begin_class_declaration這個函數,它用來創建並初始化一個zend_class_entry
類的所有信息都保存在這個結構中,那麼屬性以及方法是怎麼保存的呢?
1
2
3
class{
還記得上一篇說過的zend_initialize_class_data函數嗎?不記得也沒關係.我們仔細來瞧瞧這個函數zend_initialize_class_data(new_class_entry, 1
7
8
2021222324 252627282930313 37383940 4142434445464748
3
54
55
56
57
58
59
60
61
62
ZEND_APIvoidzend_initialize_class_data(fre_class
{
zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;
dtor_func_t zval_ptr_dtor_func = ((persistent_hashes) ? ce->refcount = 1;
ce->constants_updated = 0;
;
ce->doc_comment = NULL;
_hash_init_ex(&ce->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
zend_hash_in
zend_ properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? zend_destroy_property_info_internal : zend_destroy_property_info), persistent_hashes,) 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); zend_hash_init_ex(&ce->constants_table, 0 , NULL, zval_ptr_dtor_func, persistent_hashes, 0); zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_F1,D,o);if(ce->type == ZEND_INTERNAL_CLASS) {
#ifdef ZTS
intn = zend_hash_num_elements(CG(class_table));
embers) && n >= CG(last_static_member)) { CG(last_static_member) = n+1; CG(static_members) =realreal88,00m CG(static_members) =realreal8(H未來)> CG(static_members)[n] = NULL; } ce->static_members = (HashTable*)(zend_intptr_t)n; static_members = NULL;#endif }else{ ; }? NULL;
ce->__get = NULL; ce- >__set = NULL; ce->__unset = NULL; ce->__isset = NULL; ce->__call = NULL;ce ->__callstatic = NULL;
ce->__tostring = NULL;
ce-> ce ce->interface_gets_implemented = NULL;
ce->get_static_method = NULL;
ce 0;
ce->interfaces = NULL ;
ce->ser ialize = NULL;
ce->unserialize = NULL ;
ce->uns erialize_func = NULL;
}
zend_bool permanent_hashes = (ce->type = = ZEND_INTERNAL_CLASS)? 1 : 0;
普通用戶類別與內部類別分配記憶體的方式不同….為什麼還有差別呢? - >default_properties, 0, NULL, zval_ptr_dtor_func, permanent_hashes, 0);zend_hash_init_ex(&ce->default_static_members, 0, NULL, zval_ptr_dtor_func, perman_members, p. 0, NULL , ptr_dtor_func,persist_hashes, 0);
zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, permanent_hashes, 0);如果你看過這篇文章,那麼你肯定知道這是在初始化HashTable。是這樣,
default_properties,default_static_members等都是HashTable類型的指標.所以初始化當然要zend_hash_init了.第36-61行初始化魔術方法
不過這裡只是初始化哦..好像並沒有設定屬性.$name屬性是如何加到屬性表裡的呢??? 1234567
5
6
12
13
14
15
16
17
18
19
20
2021119
20
23211 526 unticked_class_declaration_statement: T_STRING自延伸
{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
implements_list
'{'
class_statement_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
| interface_entry T_STRING
{且如 N5, N$19 }
interface_extends_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); };class_statement: variable_modifiers { CG(access_type) = Z_LVALstant.u. } class_variable_declaration';' | class_constant_declaration';' | method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); }'(' parameter_list')'method_body { zend_do_abstract_method(&$4)$ zend_do_end_function_declaration(&$2 TSRMLS_CC); };class_variable_declaration: { zend_do_declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); } | class_variable_declaration','T_VARIABLE'='static_scalar { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); } | T_VARIABLE type) TSRMLS_CC); } | T_VARIABLE'='static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); }; 這個還記得吧?類初始化成功後類別裡面的東西當然要執行class_statement_list這個啦..^.^
類體裡會呼叫🜎2
3
4
5
6
7
8
9
10
15161718 192021222324250 31323334 3536373839
40
41
42
43
44 TSRMLS_DC)/* {{ { */
{
zval *屬性;
zend_property_info *existing_property_info;
char*comment = NULL;
if(CG(active_class_entry) ->ce_flags & ZEND_ACC_INTERFACE) {
變項");
}
zend_error(E_COMPILE_ERROR,"屬性不能宣告為抽象");
}
_ (E_COMPILE_ERROR,"無法宣告屬性%s::$%s Final,final 修飾詞只適用於方法與類別",
CG(active_class_entry)->name, var_name->u.constant.value。 ;
}
if(zend_hash_find(&CG(active_class_entry)-prodm-mR. ue.str .len+1, (void **) &existing_property_info)==SUCCESS) {
if(!(existing_property_info- zend_error (E_COMPILE_ERROR,"無法重新宣告%s::$%s" , CG(active_class_entry)-> name, var_name->u.constant.value.str.val);
}
;if(值) { }else{ Z_TYPE_P(屬性) = IS_NULL; } 評論= CG(doc_comment); comment_len = CG (doc_comment_len); CG(doc_comment) = NULL; } zend_declare_property_ex(CG(active_class_entry), var_name->; u.str. var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); efree(var_name->u.constant.value.
第8-25行:
如果你的類別宣告的是介面.那麼該介面是不能有屬性的會拋出Interfaces may not include member variables
如果類別的屬性被設定為abstract,那麼就會拋出Properties cannot be declared abstract
如果類別的屬性被設定為final,那麼會拋出Cannot declare property %s::$%s final, the final modifier is allowed only for methods and classes
一切沒有問題,會分配一個zval的資料,
如果屬性有初始值,那麼該資料會分配給zval,如果沒有,則呼叫INIT_PZVAL初始化zval,並設定類型為IS_NULL;
最後會呼叫zend_declare_property_ex將該zval加入指定的active_class_entry中
類的方法
類的方法
類的方法類的方法
類的方法類的方法
類的方法類的方法
類的方法類的方法
類的方法類
12345 class echo1; }
}
?是怎麼處理的?
先看規則 12345 variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration';' | class_constant_declaration';'ING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); }'('
{ zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
gin
熟嗎?
如果看過之前的文章,肯定眼熟
如果沒有看過.先去看看這篇文章. 函數的定義
這裡就不詳細講了.
只說說在那篇沒提到的內容
在這個函數中有一個判斷
1
2
3
4
5
6
17
5
6
1 if(is_method) { if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { ZEND_ACC_PUBLIC))) { s::%s() must be omitted", CG(active_class_entry)->name, function_name->u.constant.value.str.val); Z_LVAL(fn_flags_znode->u.constant) |= ZEND_ACC_ABSTRACT;/* propagates to the rest of the parser */ } _znode->u.constant);/* must be done *after* the above check */ }else{ fn_flags = 0; } 很明顯,如果是方法,那麼就會進去處理3-5行會拋出Access type for interface method %s::%s() must be omitted然後會呼叫
if (zend_hash_add(&CG(active_class_entry)->function_table, lcname, name_len+1, &op_array, size(arrazend, conofzend) void **) &CG(active_op_array)) == FAILURE) {zend_error(E_COMPILE_ERROR, “Cannot redeclare %s::%s()”, CG(active_class_entry)->name, name);
}直接把方法加到方法上到function_table裡.
下面會根據不同的類別聲明做不同的判斷. 以上就是原創:PHP核心研究之類的成員屬性與方法的內容,更多相關內容請關注PHP中文網(www.php.cn)!