首頁  >  文章  >  後端開發  >  原創:PHP核心研究之類的成員屬性與方法

原創:PHP核心研究之類的成員屬性與方法

黄舟
黄舟原創
2016-12-22 09:58:271262瀏覽

這篇要詳細講講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

9

10

11

12

13

14

15

20

21

22

23

24

25

26

27

28

29

30

313

37

38

39

40

41

42

43

44

45

46

47

48

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屬性是如何加到屬性表裡的呢???

1

2

3

4

5

6

7


5

6

12

13

14

15

16

17

18

19

20

20211

19

20

23211 5

26

   

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

15

16

17

18

19

20

21

22

23

24

250

31

32

33

34

35

36

37

38

39

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中
類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

類的方法

1

2

3

4

5

   

class        echo1;

      }


}

   

?是怎麼處理的?

先看規則

1

2

3

4

5

     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

1

7

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


陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn