Cet article parlera en détail des attributs et méthodes des membres des classes PHP.
Dans l'article précédent, nous avons présenté la fonction zend_do_begin_class_declaration, qui est utilisée pour créer et initialiser un zend_class_entry
Toutes les informations du la classe est enregistrée dans Dans cette structure, comment les propriétés et les méthodes sont-elles stockées
1
2
3 classPerson{ public$name;} Vous vous souvenez également de la fonction zend_initialize_class_data mentionnée dans l'article précédent ? Peu importe si vous ne vous en souvenez pas. Regardons cette fonction de plus prèszend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
ZEND_APIvoidzend_initialize_class_data(zend_class_entry *ce , zend_bool nullify_handlers TSRMLS_DC)/ * {{ { */
{
zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? ) ;
ce->refcount = 1;
ce->constants_updated = 0;
ce->ce_fla gs = 0 ;
ash_init_ex(&ce ->default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0);
zend_hash_init_ex(&ce->properties_info, 0, NULL, (dtor_func_t) (persistent_hashes ? ternal : erty_info), persistent_hashes, 0); );
zend_hash_init_ex(&ce->function_table, 0, NULL, ZEND_FUNCTION_DTOR, persistent_hashes, 0);
if(ce->type == ZEND_INTERNAL_CLASS) {
#ifdef ZTS
intn = zend_hash_num_elements(CG(class_table));
if(CG(static_members) && n >= CG(last_static_member)) {
CG(static_members) =realloc(CG(static_members), ( n 1)*sizeof(HashTable*));
CG(static_members)[n] = NULL;
}
ce ->static_members = (HashTable*) (zend_intptr_t)n;
#else
ce->static_members = NULL;
#endif
}else{
ce->static_members = &ce->default_static_members;
}
if(nullify_handlers) {
ce->constructor = NULL;
ce->destructor = NULL;
ce->clone = NULL;
ce->__get = NULL;
ce->__set = NULL;
ce->__unset = NULL;
ce- >__isset = NULL;
ce->__call = NULL;
ce->__callstatic = NULL;
ce-> __tostring = NULL;
ce->create_object = NULL;
ce->get_iterator = NULL;
ce->iterator_funcs.funcs = NULL ;
ce- >interface_gets_implemented = NULL;
ce->get_static_method = NULL;
ce->parent = NULL;
ce->num_interfaces = 0;
ce-> unserialize = NULL; ce->serialize_func = NULL; ce->unserialize_func = NULL; ce->builtin_functions = NULL; }} zend_bool persistent_hashes = (ce->type == ZEND_INTERNAL_CLASS) ? 1 : 0;普通用户类与内部类 分配内存的方式不同…. ^.^
注意看13-16行.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_FUNCTION_DTOR, persistent_hashes, 0);
如果你看过之前的文章,那么你Il s'agit d'un HashTable.是的..初始化当然要zend_hash_init了.
第36-61行初始化魔术方法
不过这里只是初始化哦..好像并没有设置属性.$name属性是如何添加到属性表里的呢???
1
2
3
{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); antecedents _statement_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
| interface_entry T_STRING
{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
interface_extends_list
'{'
class_statement_list
'}'{ zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
;
class_statement:
variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } 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, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;
class_variable_declaration:
class_variable_declaration','T_VARIABLE e_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 { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); }
| T_VARIABLE'='static_scalar { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); antecedents Il s'agit d'un class_statement_list.. ^.^
类体里会调用 zend_do_declare_property处理. 12345
6
121314151617181920212223242526272829303132 333435363738
39
40
41
42
43
44
voidzend_do_declare_property(constznode *var_name,constznode *value, zend_uint access_type TSRMLS_DC)/* {{{ */
{
zval *property;
zend_property_info *existing _property_info;
char*comment = NULL;
intcomment_len = 0;
if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
zend_error(E_COMPILE_ERROR, "Les interfaces ne peuvent pas inclure de variables membres");
}
if(access_type & ZEND_ACC_ABSTRACT {
zend_error (E_COMPILE_ERROR,"Les propriétés ne peuvent pas être déclarées abstraites"); } if(access_type & ZEND_ACC_FINAL) { zend_error(E_ COMPILE_ERROR,"Impossible déclarer la propriété %s::$%s final, le modificateur final n'est autorisé que pour les méthodes et les 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 1, (void**) &existing_property_info)==SUCCESS) { if(!(existing_property_info->flags & ZEND_ACC_IMPLICIT_PUBLIC)) { zend_error(E_COMPILE_ERROR, "Impossible de redéclarer %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); } } ALLOC_ZVAL(propriété); si(valeur) { *propriété = valeur-> u.constant ; }else{ INIT_PZVAL(propriété); Z_TYPE_P(propriété) = IS_NULL; }if(CG(doc_comment)) { comment = CG(doc_comment); comment_len = CG(doc_comment_len); CG(doc_comment) = NULL ; > .constant.value.str .val, var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); efree(var_name->u.constant.value.str.val); }
Ligne 8-25 :
Si votre classe déclare une interface, alors l'interface ne peut pas avoir d'attributs et lancera Les interfaces ne peuvent pas inclure de variables membres
Si les attributs de la classe sont définis sur abstrait, alors elle le fera throw Les propriétés ne peuvent pas être déclarées abstraites
Si les propriétés de la classe sont définies sur final, alors elle lancera Impossible de déclarer la propriété %s::$%s final, le modificateur final n'est autorisé que pour les méthodes et les classes
Tout c'est bien, une donnée zval sera allouée.
Si l'attribut a une valeur initiale, alors les données seront affectées au zval. Sinon, INIT_PZVAL sera appelé pour initialiser le zval et le type est défini sur IS_NULL ;
Enfin, zend_declare_property_ex sera appelé Ajouter le zval à l'active_class_entry spécifié
Méthodes de la classe
1
2
3
4
5
classPerson{
publicfunctiontest(){
echo1;
}
}
Et si c'est une méthode ? Comment est-elle gérée ?
Regardez d'abord les règles
1
2
3
4
5
class_statement :
CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration';'
| gin_function_declaration(&$2, &$4, " RMLS_CC); }
Le premier est l'attribut, puis le troisième est la méthode...
Zend_do_begin_function_declaration vous semble-t-il familier ?Si vous avez lu le précédent article, vous devez Cela vous semble familier
Si vous ne l'avez pas lu, allez d'abord lire cet article La définition de la fonctionJe n'entrerai pas dans les détails ici.
Je vais juste parler de ce qui était. non mentionné dans cet article
Dans cette fonction Il y a un jugement en
1
2
3
4
5
6
7
8
9
10
11
if (is_method) {
if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
if((Z_LVAL(fn_flags_znode-&g t;u.constant) & ~(ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) :) .str.val);
reste de l'analyseur */
}
fn_flags = Z_LVAL( fn_flags_znode->u.constant); fn_flags = 0;
}
Si vous définissez les propriétés de la classe d'interface sur privée ou protégée, alors Type d'accès pour la méthode d'interface %s ::%s() doit être omis
sera lancé puisif (zend_hash_add() sera appelé &CG(active_class_entry)->function_table, lcname, name_len 1, &op_array, sizeof(zend_op_array), ( void **) &CG(active_op_array)) == FAILURE) {
zend_error(E_COMPILE_ERROR, "Impossible de redéclarer %s:: %s()", CG(active_class_entry)->name, name);}
Ajoutez la méthode directement à la function_table.Ce qui suit fera différents jugements basés sur différentes déclarations de classe.
Ce qui précède est le contenu original : recherche du noyau PHP et autres attributs et méthodes des membres. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !