Rumah pembangunan bahagian belakang tutorial php 原创:PHP内核研究之类的成员属性和方法

原创:PHP内核研究之类的成员属性和方法

Dec 22, 2016 am 09:58 AM

这一篇要详细讲讲PHP类的成员属性及方法.
上一篇中曾经介绍到zend_do_begin_class_declaration这个函数,它用来创建并初始化一个zend_class_entry
类的所有信息都保存在这个结构中,那么 属性和方法是怎么保存的呢?


1

2

3

   

classPerson{

      public$name;

}

   

还记得上一篇说过的zend_initialize_class_data函数吗?不记得也没关系.我们仔细来瞧瞧这个函数
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

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) ? 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;
普通用户类与内部类 分配内存的方式不同….为什么会有区别呢???我还没来得及研究哦..^.^
注意看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);

}

   

第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

   

classPerson{

      publicfunctiontest(){

             echo1;

      }

}

   

如果是方法呢??是怎么处理的?
先看规则

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

                        parameter_list')'method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }

   

第一个是属性,那么第三个就是就是方法啦..
zend_do_begin_function_declaration眼熟吗?
如果看过之前的文章,肯定眼熟
如果没有看过.先去看看这篇文章. 函数的定义
这里就不详细讲了.
只说说在那篇没提到的内容
在这个函数中 有一个判断

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 be done *after* the above check */

        }else{

                fn_flags = 0;

        }

   

很明显,如果是方法 ,那么才会进去处理
3-5行 :
如果你把接口类的属性设置为private私有或受保护的.那么就会抛出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, 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);
}
直接把方法添加到function_table里.
下面会根据不同的类声明做不同的判断.

 以上就是原创:PHP内核研究之类的成员属性和方法的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Arahan sembang dan cara menggunakannya
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk memadam rakan WeChat? Bagaimana untuk memadam rakan WeChat Bagaimana untuk memadam rakan WeChat? Bagaimana untuk memadam rakan WeChat Mar 04, 2024 am 11:10 AM

WeChat ialah salah satu alat sembang arus perdana Kami boleh bertemu rakan baru, menghubungi rakan lama dan mengekalkan persahabatan antara rakan melalui WeChat. Sama seperti tidak ada jamuan yang tidak pernah berakhir, perselisihan faham akan berlaku apabila orang ramai bergaul antara satu sama lain. Apabila seseorang sangat mempengaruhi mood anda, atau anda mendapati pandangan anda tidak konsisten apabila anda bergaul, dan anda tidak boleh terus berkomunikasi, maka kami mungkin perlu memadamkan rakan WeChat. Bagaimana untuk memadam rakan WeChat? Langkah pertama untuk memadam rakan WeChat: ketik [Buku Alamat] pada antara muka utama WeChat langkah kedua: klik pada rakan yang ingin anda padamkan dan masukkan [Butiran]; sudut kanan; Langkah 4: Klik [Padam] di bawah Langkah 5: Selepas memahami gesaan halaman, klik [Padam Kenalan];

Cara menulis novel dalam aplikasi Novel Percuma Tomato Kongsi tutorial cara menulis novel dalam Novel Tomato. Cara menulis novel dalam aplikasi Novel Percuma Tomato Kongsi tutorial cara menulis novel dalam Novel Tomato. Mar 28, 2024 pm 12:50 PM

Novel Tomato adalah perisian membaca novel yang sangat popular Kami sering mempunyai novel dan komik baru untuk dibaca dalam Novel Tomato Setiap novel dan komik sangat menarik ingin menulis ke dalam teks. Jadi bagaimana kita menulis novel di dalamnya? Kongsi tutorial novel Tomato tentang cara menulis novel 1. Mula-mula buka aplikasi novel percuma Tomato pada telefon bimbit anda dan klik pada Pusat Peribadi - Pusat Penulis 2. Lompat ke halaman Pembantu Penulis Tomato - klik pada Buat buku baru di penghujung novel.

Bagaimana untuk memasukkan bios pada papan induk Berwarna-warni? Ajar anda dua kaedah Bagaimana untuk memasukkan bios pada papan induk Berwarna-warni? Ajar anda dua kaedah Mar 13, 2024 pm 06:01 PM

Papan induk berwarna-warni menikmati populariti tinggi dan bahagian pasaran dalam pasaran domestik China, tetapi sesetengah pengguna papan induk Berwarna-warni masih tidak tahu cara memasukkan bios untuk tetapan? Sebagai tindak balas kepada situasi ini, editor telah membawakan anda secara khas dua kaedah untuk memasukkan bios motherboard yang berwarna-warni. Datang dan cuba! Kaedah 1: Gunakan kekunci pintasan permulaan cakera U untuk terus memasuki sistem pemasangan cakera U Kekunci pintasan untuk papan induk Berwarna untuk memulakan cakera U dengan satu klik ialah ESC atau F11 Pertama, gunakan Black Shark Installation Master untuk mencipta Black Cakera but cakera Shark U, dan kemudian hidupkan komputer Apabila anda melihat skrin permulaan, tekan terus kekunci ESC atau F11 pada papan kekunci untuk memasuki tetingkap untuk pemilihan item permulaan secara berurutan ke tempat "USB " dipaparkan, dan kemudian

Bagaimana untuk memulihkan kenalan yang dipadam pada WeChat (tutorial mudah memberitahu anda cara memulihkan kenalan yang dipadam) Bagaimana untuk memulihkan kenalan yang dipadam pada WeChat (tutorial mudah memberitahu anda cara memulihkan kenalan yang dipadam) May 01, 2024 pm 12:01 PM

Malangnya, orang sering memadamkan kenalan tertentu secara tidak sengaja atas sebab tertentu WeChat ialah perisian sosial yang digunakan secara meluas. Untuk membantu pengguna menyelesaikan masalah ini, artikel ini akan memperkenalkan cara mendapatkan semula kenalan yang dipadam dengan cara yang mudah. 1. Fahami mekanisme pemadaman kenalan WeChat Ini memberi kita kemungkinan untuk mendapatkan semula kenalan yang dipadamkan Mekanisme pemadaman kenalan dalam WeChat mengalih keluar mereka daripada buku alamat, tetapi tidak memadamkannya sepenuhnya. 2. Gunakan fungsi "Pemulihan Buku Kenalan" terbina dalam WeChat menyediakan "Pemulihan Buku Kenalan" untuk menjimatkan masa dan tenaga Pengguna boleh mendapatkan semula kenalan yang telah dipadamkan dengan cepat melalui fungsi ini. 3. Masuk ke halaman tetapan WeChat dan klik sudut kanan bawah, buka aplikasi WeChat "Saya" dan klik ikon tetapan di sudut kanan atas untuk memasuki halaman tetapan.

Ringkasan kaedah untuk mendapatkan hak pentadbir dalam Win11 Ringkasan kaedah untuk mendapatkan hak pentadbir dalam Win11 Mar 09, 2024 am 08:45 AM

Ringkasan cara mendapatkan hak pentadbir Win11 Dalam sistem pengendalian Windows 11, hak pentadbir adalah salah satu kebenaran yang sangat penting yang membolehkan pengguna melakukan pelbagai operasi pada sistem. Kadangkala, kami mungkin perlu mendapatkan hak pentadbir untuk menyelesaikan beberapa operasi, seperti memasang perisian, mengubah suai tetapan sistem, dsb. Berikut meringkaskan beberapa kaedah untuk mendapatkan hak pentadbir Win11, saya harap ia dapat membantu anda. 1. Gunakan kekunci pintasan Dalam sistem Windows 11, anda boleh membuka gesaan arahan dengan cepat melalui kekunci pintasan.

Bagaimana untuk menetapkan saiz fon pada telefon mudah alih (mudah melaraskan saiz fon pada telefon bimbit) Bagaimana untuk menetapkan saiz fon pada telefon mudah alih (mudah melaraskan saiz fon pada telefon bimbit) May 07, 2024 pm 03:34 PM

Menetapkan saiz fon telah menjadi keperluan pemperibadian yang penting kerana telefon mudah alih menjadi alat penting dalam kehidupan seharian manusia. Untuk memenuhi keperluan pengguna yang berbeza, artikel ini akan memperkenalkan cara meningkatkan pengalaman penggunaan telefon mudah alih dan melaraskan saiz fon telefon mudah alih melalui operasi mudah. Mengapa anda perlu melaraskan saiz fon telefon mudah alih anda - Melaraskan saiz fon boleh menjadikan teks lebih jelas dan mudah dibaca - Sesuai untuk keperluan membaca pengguna yang berbeza umur - Mudah untuk pengguna yang kurang penglihatan menggunakan saiz fon fungsi tetapan sistem telefon mudah alih - Cara memasukkan antara muka tetapan sistem - Dalam Cari dan masukkan pilihan "Paparan" dalam antara muka tetapan - cari pilihan "Saiz Fon" dan laraskan saiz fon dengan pihak ketiga aplikasi - muat turun dan pasang aplikasi yang menyokong pelarasan saiz fon - buka aplikasi dan masukkan antara muka tetapan yang berkaitan - mengikut individu

Rahsia penetasan telur naga mudah alih terbongkar (langkah demi langkah untuk mengajar anda cara berjaya menetas telur naga mudah alih) Rahsia penetasan telur naga mudah alih terbongkar (langkah demi langkah untuk mengajar anda cara berjaya menetas telur naga mudah alih) May 04, 2024 pm 06:01 PM

Permainan mudah alih telah menjadi sebahagian daripada kehidupan orang ramai dengan perkembangan teknologi. Ia telah menarik perhatian ramai pemain dengan imej telur naga yang comel dan proses penetasan yang menarik, dan salah satu permainan yang telah menarik perhatian ramai ialah versi mudah alih Dragon Egg. Untuk membantu pemain memupuk dan mengembangkan naga mereka sendiri dengan lebih baik dalam permainan, artikel ini akan memperkenalkan kepada anda cara menetas telur naga dalam versi mudah alih. 1. Pilih jenis telur naga yang sesuai Pemain perlu berhati-hati memilih jenis telur naga yang mereka suka dan sesuai dengan diri mereka, berdasarkan pelbagai jenis sifat dan kebolehan telur naga yang disediakan dalam permainan. 2. Tingkatkan tahap mesin pengeraman Pemain perlu meningkatkan tahap mesin pengeraman dengan menyelesaikan tugasan dan mengumpul prop Tahap mesin pengeraman menentukan kelajuan penetasan dan kadar kejayaan penetasan. 3. Kumpul sumber yang diperlukan untuk penetasan Pemain perlu berada dalam permainan

Penjelasan terperinci tentang kaedah pertanyaan versi Oracle Penjelasan terperinci tentang kaedah pertanyaan versi Oracle Mar 07, 2024 pm 09:21 PM

Penjelasan terperinci tentang kaedah pertanyaan versi Oracle Oracle ialah salah satu sistem pengurusan pangkalan data hubungan yang paling popular di dunia Ia menyediakan fungsi yang kaya dan prestasi yang berkuasa dan digunakan secara meluas dalam perusahaan. Dalam proses pengurusan dan pembangunan pangkalan data, adalah sangat penting untuk memahami versi pangkalan data Oracle. Artikel ini akan memperkenalkan secara terperinci cara untuk menanyakan maklumat versi pangkalan data Oracle dan memberikan contoh kod khusus. Tanya versi pangkalan data pernyataan SQL dalam pangkalan data Oracle dengan melaksanakan pernyataan SQL yang mudah

See all articles