Original: Member properties and methods such as PHP kernel research

Source: Internet
Author: User
This article details the member properties and methods of the PHP class.
In the previous article, I introduced the Zend_do_begin_class_declaration function, which is used to create and initialize a zend_class_entry
All of the information in the class is stored in this structure, so how are the properties and methods stored?


1

2

3

classperson{

Public$name;

}

Remember the previous Zend_initialize_class_data function? It doesn't matter if you don't remember. Let's take a closer look at this function.
Zend_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

21st

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)? 1:0;

dtor_func_t Zval_ptr_dtor_func = ((persistent_hashes)? Zval_internal_ptr_dtor:zval_ptr_dtor);

Ce->refcount = 1;

ce->constants_updated = 0;

ce->ce_flags = 0;

Ce->doc_comment = NULL;

Ce->doc_comment_len = 0;

ZEND_HASH_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? zend_destroy_property_ Info_internal:zend_destroy_property_info), persistent_hashes, 0);

ZEND_HASH_INIT_EX (&ce->default_static_members, 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_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)) {

/* Support for Run-time DECLARATION:DL () */

CG (last_static_member) = n+1;

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->interfaces = NULL;

Ce->module = NULL;

Ce->serialize = NULL;

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;
Ordinary user classes have different ways of allocating memory to internal classes .... Why is there a difference???? I haven't had a chance to study it yet. ^.^
Take a look at line 13-16.
ZEND_HASH_INIT_EX (&ce->default_properties, 0, NULL, Zval_ptr_dtor_func, persistent_hashes, 0);
ZEND_HASH_INIT_EX (&ce->default_static_members, 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_function_dtor, persistent_hashes, 0);
If you have read the previous article, then you certainly know that it is in the initialization of Hashtable.
Yes.. Yes, it does.
Default_properties,default_static_members, etc. are all pointers to the Hashtable type. So the initialization of course is going to zend_hash_init.
第36-61 the Magic method of line initialization
But this is just the initialization, OH. It does not seem to have a property set. How $name property is added to the property table???

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21st

22

23

24

25

26

Unticked_class_declaration_statement:

Class_entry_type t_string Extends_from

{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

{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, & Amp;$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 {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 {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);}

;

You remember that, don't you?
After the class is initialized successfully, the contents of the class must be executed class_statement_list. ^.^
Zend_do_declare_property processing is called in the class body.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21st

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

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, "Interfaces may not include member variables");

}

if (Access_type & zend_acc_abstract) {

Zend_error (E_compile_error, "Properties cannot be declared abstract");

}

if (Access_type & zend_acc_final) {

Zend_error (E_compile_error, "cannot declare property%s::$%s final, the final modifier was allowed only for methods and Clas Ses ",

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, "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) = 0;

}

ZEND_DECLARE_PROPERTY_EX (CG (active_class_entry), Var_name->u.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);

}

第8-25 Line:
If your class declares an interface, then the interface is not able to have attributes that will throw interfaces may not include member variables
If the property of the class is set to abstract, then the properties cannot be declared abstract
If the class's properties are set to final, then the cannot declare property%s::$%s final will be thrown, the final modifier is allowed just for methods and classes
Everything is no problem, will allocate a zval of data,
If the property has an initial value, then the data is assigned to Zval, and if not, call Init_pzval to initialize Zval and set the type to Is_null;
Finally, ZEND_DECLARE_PROPERTY_EX is called to add the Zval to the specified active_class_entry
Methods of the class

1

2

3

4

5

classperson{

Publicfunctiontest () {

Echo1;

}

}

What if it's a method?? What's the deal?
Look at the rules first.

1

2

3

4

5

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, & Amp;$1 tsrmls_cc); }'('

Parameter_list ') ' Method_body {zend_do_abstract_method (&$4, &$1, &$9 tsrmls_cc); zend_do_end_function_ Declaration (&$2 TSRMLS_CC); }

The first one is the attribute, then the third is the method.
Does zend_do_begin_function_declaration look familiar?
If you read the previous article, it must look familiar.
If you have not seen it. Read the article first. Definition of function
This is not a detailed story.
Just talk about what you didn't mention in that article.
There's a judgment in this function.

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->u.constant) & ~ (zend_acc_static| Zend_acc_public)) {

Zend_error (E_compile_error, "Access type for Interface method%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 * *

}

Fn_flags = Z_lval (fn_flags_znode->u.constant);/* must is done *after* the above check */

}else{

fn_flags = 0;

}

Obviously, if it's a method, it's going to go in.
3-5 lines:
If you set the properties of the interface class to private or protected. Then it throws access type for interface method%s::%s () must is omitted
It then calls
if (Zend_hash_add (&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, "Cannot redeclare%s::%s ()", CG (active_class_entry)->name, name);
}
Add the method directly to the function_table.
The following will make different judgments based on the different class declarations.

The above is the original: PHP kernel research and other member properties and methods of content, more relevant content please pay attention to topic.alibabacloud.com (www.php.cn)!

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.