Home  >  Article  >  Backend Development  >  Original: PHP kernel research such member attributes and methods

Original: PHP kernel research such member attributes and methods

黄舟
黄舟Original
2016-12-22 09:58:271257browse

This article will talk about the member attributes and methods of PHP classes in detail.
In the previous article, we introduced the zend_do_begin_class_declaration function, which is used to create and initialize a zend_class_entry
All the information of the class is saved in this structure, then the attributes How are the methods and methods saved?


1

2

3

I still remember what I said in the previous article 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);

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

5 3

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-&g t;refcount = 1;

ce->constants_updated = 0;

ce-> ;ce_flags = 0;

ce->doc_comment = NULL; ce->doc_comment_len = 0;

zend_hash_init_ex(&ce-&g t;default_properties, 0, NULL, zval_ptr_dtor_func, persistent_hashes, 0); Zen d_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); ;

if(ce-> ;type == ZEND_INTERNAL_CLASS) {

#ifdef ZTS

                        intn = zend_hash_num_elements(CG(class_table));                                       t;= CG(last_static_member)) {

                                                                                                                            for run-time declaration: dl() */

                  CG(last_static_member)                                                                                                         );

                     CG(static_members)[n] = NULL;

#else

      ce->static_members = NULL;

#endif

                                                                                                                                                  

        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;
普通用户类与内部类 分配内存的方式不同….为什么会有区别呢???我还没来得及研究哦..^.^
注意看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);
如果你看过之前的文章,那么你肯定知道这是在初始化HashTable.
是的..确实是这样,
default_properties,default_static_members等都是HashTable类型的指针.所以初始化当然要zend_hash_init了.
第36-61行初始化魔术方法
不过这里只是初始化哦..好像并没有设置属性.$name属性是如何添加到属性表里的呢???

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

   

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

;

   

这个还记得吧?
类初始化成功后类里面的东西当然要执行class_statement_list这个啦..^.^
类体里会调用 zend_do_declare_property处理.

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

   

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 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+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);

}

   

Lines 8-25:
If your class declares an interface, then the interface cannot have attributes and Interfaces may not include member variables will be thrown.
If the attributes of the class are set to abstract, then Properties cannot be thrown. be declared abstract
If the property of the class is set to final, then Cannot declare property %s::$%s final will be thrown, the final modifier is allowed only for methods and classes
Everything is fine, a zval data will be allocated ,
If the attribute has an initial value, then the data will be assigned to the zval. If not, INIT_PZVAL is called to initialize the zval and the type is set to IS_NULL;
Finally, zend_declare_property_ex will be called to add the zval to the specified active_class_entry
Method of the class

1

2

3

4

5

classPerson{

public functiontest(){

echo1;

       }

}

   

What if it’s the method?? How to deal with it?
Look at the rules first

1

2

3

4

5

class_statement:

                             (access_type) = Z_LVAL($1.u.constant); } class_variable_declaration';'

| RMLS_CC); }'('

                                                                                                                                                                                           { 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 one is the method...

zend_do_begin_function_declaration Does it look familiar?

If you have read the previous article, you will definitely look familiar
If you haven’t read it, go read this article first. The definition of function
I won’t go into details here.
I will only talk about the content that was not mentioned in that article
In this function There is a judgment in

1

2

3

4

5

6

7

8

9

10

11

if(is_method) {

if(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {

                                                                                      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);

                                         (fn_flags_znode->u .constant) |= ZEND_ACC_ABSTRACT;/* propagates to the rest of the parser */

                                                                                                                               */

                                                                                                                           The properties of the class are set to private or Protected. Then Access type for interface method %s::%s() must be omitted will be thrown and then called

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 different class declarations.

The above is the original content: PHP kernel research and other member attributes and methods. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn