Rumah pembangunan bahagian belakang tutorial php 原创:PHP内核研究之类的实现

原创:PHP内核研究之类的实现

Dec 22, 2016 am 09:56 AM

这几天比较忙哦..没有时间写..周末了多写几篇吧.
目前大部分语言都支持类.
类是什么?类就是面向对象,简称OOP.英文名字 Object Oriented Programming.
面向对象是什么?是一种编程架构.
OOP的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个目标:重用性、灵活性和扩展性.
因为我们讲的不是这里只简单描述,如果你还不知道什么是类,什么是面向对象..那么这篇文章目前不适合你哦.

classPerson{

  

};

   

上面是创建一个PHP类.class是PHP的关键字.通过它我们就能找到Zend是如何创建类的.


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_entry_type:

                T_CLASS                 { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = 0; }

        |       T_ABSTRACT T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }

        |       T_FINAL T_CLASS { $$.u.opline_num = CG(zend_lineno); $$.u.EA.type = ZEND_ACC_FINAL_CLASS; }

;

   

T_CLASS,T_ABSTRACT T_CLASS和T_FINAL 是PHP的三种类的模式
T_CLASS:是一个标准类.
T_ABSTRACT:是声明一个抽象类
T_FINAL:声明一个不容许继承和扩展的类.
当然还有interface
他们定义在Zend/zend_complie.h的文件中

   

#define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10    //没有声明为抽象,但是内部有抽象方法

#define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS    0x20   //抽象

#define ZEND_ACC_FINAL_CLASS                0x40  //Final

#define ZEND_ACC_INTERFACE                  0x80 //接口

   

这三个规则 记录当前行,并设置类的类型.
在定义类的时候调用了 zend_do_begin_class_declaration和zend_do_end_class_declaration两个方法,
类的关键字 ,类的名称和所继承的父类作为参数传递给这两个函数.
zend_do_begin_class_declaration是用来声明类,设置类型,创建一个
zend_do_end_class_declaration用来处理类中的属性及方法.
在讲到两个函数之前一定先要说说 保存类的结构zend_class_entry
它定义在Zend/zend.h中


struct_zend_class_entry {

        chartype;

        char*name;//类名称

        zend_uint name_length;

        struct_zend_class_entry *parent;//所继承的父类

        intrefcount; //引用数

        zend_bool constants_updated;//类的类型

        zend_uint ce_flags;//类的类型 抽象?接口?Final?

        HashTable function_table; //函数表

        HashTable default_properties;//属性

        HashTable properties_info; //函数的访问级别

        HashTable default_static_members;//静态成员

        HashTable *static_members;//静态成员,当是用户声明的类等于default_static_members,内置的类为NULL

        HashTable constants_table;

        conststruct_zend_function_entry *builtin_functions;

       //眼熟吗???对的.魔术函数在这里哦..

        union_zend_function *constructor;

        union_zend_function *destructor;

        union_zend_function *clone;

        union_zend_function *__get;

        union_zend_function *__set;

        union_zend_function *__unset;

        union_zend_function *__isset;

        union_zend_function *__call;

        union_zend_function *__callstatic;

        union_zend_function *__tostring;

        union_zend_function *serialize_func;

        union_zend_function *unserialize_func;

  

        zend_class_iterator_funcs iterator_funcs;

  

        /* handlers */

        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);

        zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object,intby_ref TSRMLS_DC);

        int(*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC);/* a class implements this interface */

        union_zend_function *(*get_static_method)(zend_class_entry *ce,char* method,intmethod_len TSRMLS_DC);

  

        /* serializer callbacks */

        int(*serialize)(zval *object, unsignedchar**buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);

        int(*unserialize)(zval **object, zend_class_entry *ce,constunsignedchar*buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);

  

        zend_class_entry **interfaces;

        zend_uint num_interfaces;

  

        char*filename;//声明类的文件地址

        zend_uint line_start;//类开始行

        zend_uint line_end;//类结束行

        char*doc_comment;

        zend_uint doc_comment_len;

  

        struct_zend_module_entry *module;

};

   

清楚了这个结构之后 下面来看看zend_do_begin_class_declaration函数

   

voidzend_do_begin_class_declaration(constznode *class_token, znode *class_name,constznode *parent_class_name TSRMLS_DC)/* {{{ */

{

        zend_op *opline;

        intdoing_inheritance = 0;

        zend_class_entry *new_class_entry;

        char*lcname;

        interror = 0;

        zval **ns_name;

  

        if(CG(active_class_entry)) {

                zend_error(E_COMPILE_ERROR,"Class declarations may not be nested");

                return;

        }

  

        lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);

  

        if(!(strcmp(lcname,"self") &&strcmp(lcname,"parent"))) {

                efree(lcname);

                zend_error(E_COMPILE_ERROR,"Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val);

        }

  

        /* Class name must not conflict with import names */

        if(CG(current_import) &&

                        zend_hash_find(CG(current_import), lcname, Z_STRLEN(class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) {

                error = 1;

        }

       if(CG(current_namespace)) {

                /* Prefix class name with name of current namespace */

                znode tmp;

  

                tmp.u.constant = *CG(current_namespace);

                zval_copy_ctor(&tmp.u.constant);

                zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);

                class_name = &tmp;

                efree(lcname);

                lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));

        }

  

        if(error) {

                char*tmp = zend_str_tolower_dup(Z_STRVAL_PP(ns_name), Z_STRLEN_PP(ns_name));

  

                if(Z_STRLEN_PP(ns_name) != Z_STRLEN(class_name->u.constant) ||

                        memcmp(tmp, lcname, Z_STRLEN(class_name->u.constant))) {

                        zend_error(E_COMPILE_ERROR,"Cannot declare class %s because the name is already in use", Z_STRVAL(class_name->u.constant));

                }

                efree(tmp);

        }

  

        new_class_entry = emalloc(sizeof(zend_class_entry));

        new_class_entry->type = ZEND_USER_CLASS;

        new_class_entry->name = class_name->u.constant.value.str.val;

        new_class_entry->name_length = class_name->u.constant.value.str.len;

  

        zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);

        new_class_entry->filename = zend_get_compiled_filename(TSRMLS_C);

        new_class_entry->line_start = class_token->u.opline_num;

        new_class_entry->ce_flags |= class_token->u.EA.type;

if(parent_class_name && parent_class_name->op_type != IS_UNUSED) {

                switch(parent_class_name->u.EA.type) {

                        caseZEND_FETCH_CLASS_SELF:

                                zend_error(E_COMPILE_ERROR,"Cannot use 'self' as class name as it is reserved");

                                break;

                        caseZEND_FETCH_CLASS_PARENT:

                                zend_error(E_COMPILE_ERROR,"Cannot use 'parent' as class name as it is reserved");

                                break;

                        caseZEND_FETCH_CLASS_STATIC:

                                zend_error(E_COMPILE_ERROR,"Cannot use 'static' as class name as it is reserved");

                                break;

                        default:

                                break;

                }

                doing_inheritance = 1;

        }

  

        opline = get_next_op(CG(active_op_array) TSRMLS_CC);

        opline->op1.op_type = IS_CONST;

        build_runtime_defined_function_key(&opline->op1.u.constant, lcname, new_class_entry->name_length TSRMLS_CC);

  

        opline->op2.op_type = IS_CONST;

        opline->op2.u.constant.type = IS_STRING;

        Z_SET_REFCOUNT(opline->op2.u.constant, 1);

  

        if(doing_inheritance) {

                opline->extended_value = parent_class_name->u.var;

                opline->opcode = ZEND_DECLARE_INHERITED_CLASS;

        }else{

                opline->opcode = ZEND_DECLARE_CLASS;

        }

opline->op2.u.constant.value.str.val = lcname;

        opline->op2.u.constant.value.str.len = new_class_entry->name_length;

  

        zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry,sizeof(zend_class_entry *), NULL);

        CG(active_class_entry) = new_class_entry;

  

        opline->result.u.var = get_temporary_variable(CG(active_op_array));

        opline->result.op_type = IS_VAR;

        CG(implementing_class) = opline->result;

  

        if(CG(doc_comment)) {

                CG(active_class_entry)->doc_comment = CG(doc_comment);

                CG(active_class_entry)->doc_comment_len = CG(doc_comment_len);

                CG(doc_comment) = NULL;

                CG(doc_comment_len) = 0;

        }

}

   

lcname = zend_str_tolower_dup(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
把所有类全部转换为小写处理.这就是为什么PHP大小写不敏感的原因.
if (!(strcmp(lcname, “self”) && strcmp(lcname, “parent”))) {
efree(lcname);
zend_error(E_COMPILE_ERROR, “Cannot use ‘%s’ as class name as it is reserved”, class_name->u.constant.value.str.val);
}
类的名字不能是self和parent.
第23-26行 用来检测类名是否重复定义.
第27-37行 用来设置命名空间,这是PHP5.3的新特性
第39-47行 用来抛出重复定义的错误
第49-57行 初始化保存类的结构
zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);函数是用来初始化结构里面的HashTable,魔术方法.
这个函数里面也有上面提到( HashTable *static_members; //静态成员,当是用户声明的类等于default_static_members,内置的类为NULL)的原因
第58-73行 同样用来检测父类的类名是否包含 保留关键字 self,parent,static
剩下的就是用来生成一个OP,
是内部类:那么生成的OP中间代码就是 ZEND_DECLARE_INHERITED_CLASS
是用户类:OP中间代码就是ZEND_DECLARE_CLASS
在这之后..Zend引擎会调用zend_execute函数执行OP的中间代码ZEND_DECLARE_CLASS_SPEC_HANDLER
它定义在Zend/zend_vm_execute.h中.
这个函数将执行关键代码
EX_T(opline->result.u.var).class_entry = do_bind_class(opline, EG(class_table), 0 TSRMLS_CC) ;
do_bind_class会将此类放到class_table中.当然 ,在这个函数里还会判断该类是否存在.不存在会抛出错误
Internal Zend error – Missing class information for %s
如果存在 则会添加成功
那么到这里类就创建成功了.
下一张节就要深入到 类内部了哦…

 以上就是原创: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)

Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Panduan Pemasangan dan Naik Taraf PHP 8.4 untuk Ubuntu dan Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 membawa beberapa ciri baharu, peningkatan keselamatan dan peningkatan prestasi dengan jumlah penamatan dan penyingkiran ciri yang sihat. Panduan ini menerangkan cara memasang PHP 8.4 atau naik taraf kepada PHP 8.4 pada Ubuntu, Debian, atau terbitan mereka

Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Cara Menyediakan Kod Visual Studio (Kod VS) untuk Pembangunan PHP Dec 20, 2024 am 11:31 AM

Kod Visual Studio, juga dikenali sebagai Kod VS, ialah editor kod sumber percuma — atau persekitaran pembangunan bersepadu (IDE) — tersedia untuk semua sistem pengendalian utama. Dengan koleksi sambungan yang besar untuk banyak bahasa pengaturcaraan, Kod VS boleh menjadi c

7 Fungsi PHP Saya Menyesal Saya Tidak Tahu Sebelum ini 7 Fungsi PHP Saya Menyesal Saya Tidak Tahu Sebelum ini Nov 13, 2024 am 09:42 AM

Jika anda seorang pembangun PHP yang berpengalaman, anda mungkin merasakan bahawa anda telah berada di sana dan telah melakukannya. Anda telah membangunkan sejumlah besar aplikasi, menyahpenyahpepijat berjuta-juta baris kod dan mengubah suai sekumpulan skrip untuk mencapai op

Bagaimana anda menghuraikan dan memproses HTML/XML dalam PHP? Bagaimana anda menghuraikan dan memproses HTML/XML dalam PHP? Feb 07, 2025 am 11:57 AM

Tutorial ini menunjukkan cara memproses dokumen XML dengan cekap menggunakan PHP. XML (bahasa markup extensible) adalah bahasa markup berasaskan teks yang serba boleh yang direka untuk pembacaan manusia dan parsing mesin. Ia biasanya digunakan untuk penyimpanan data

Jelaskan JSON Web Tokens (JWT) dan kes penggunaannya dalam PHP API. Jelaskan JSON Web Tokens (JWT) dan kes penggunaannya dalam PHP API. Apr 05, 2025 am 12:04 AM

JWT adalah standard terbuka berdasarkan JSON, yang digunakan untuk menghantar maklumat secara selamat antara pihak, terutamanya untuk pengesahan identiti dan pertukaran maklumat. 1. JWT terdiri daripada tiga bahagian: header, muatan dan tandatangan. 2. Prinsip kerja JWT termasuk tiga langkah: menjana JWT, mengesahkan JWT dan muatan parsing. 3. Apabila menggunakan JWT untuk pengesahan di PHP, JWT boleh dijana dan disahkan, dan peranan pengguna dan maklumat kebenaran boleh dimasukkan dalam penggunaan lanjutan. 4. Kesilapan umum termasuk kegagalan pengesahan tandatangan, tamat tempoh, dan muatan besar. Kemahiran penyahpepijatan termasuk menggunakan alat debugging dan pembalakan. 5. Pengoptimuman prestasi dan amalan terbaik termasuk menggunakan algoritma tandatangan yang sesuai, menetapkan tempoh kesahihan dengan munasabah,

Program PHP untuk mengira vokal dalam rentetan Program PHP untuk mengira vokal dalam rentetan Feb 07, 2025 pm 12:12 PM

Rentetan adalah urutan aksara, termasuk huruf, nombor, dan simbol. Tutorial ini akan mempelajari cara mengira bilangan vokal dalam rentetan yang diberikan dalam PHP menggunakan kaedah yang berbeza. Vokal dalam bahasa Inggeris adalah a, e, i, o, u, dan mereka boleh menjadi huruf besar atau huruf kecil. Apa itu vokal? Vokal adalah watak abjad yang mewakili sebutan tertentu. Terdapat lima vokal dalam bahasa Inggeris, termasuk huruf besar dan huruf kecil: a, e, i, o, u Contoh 1 Input: String = "TutorialSpoint" Output: 6 menjelaskan Vokal dalam rentetan "TutorialSpoint" adalah u, o, i, a, o, i. Terdapat 6 yuan sebanyak 6

Terangkan pengikatan statik lewat dalam php (statik: :). Terangkan pengikatan statik lewat dalam php (statik: :). Apr 03, 2025 am 12:04 AM

Mengikat statik (statik: :) Melaksanakan pengikatan statik lewat (LSB) dalam PHP, yang membolehkan kelas panggilan dirujuk dalam konteks statik dan bukannya menentukan kelas. 1) Proses parsing dilakukan pada masa runtime, 2) Cari kelas panggilan dalam hubungan warisan, 3) ia boleh membawa overhead prestasi.

Apakah kaedah Magic PHP (__construct, __destruct, __call, __get, __set, dll) dan menyediakan kes penggunaan? Apakah kaedah Magic PHP (__construct, __destruct, __call, __get, __set, dll) dan menyediakan kes penggunaan? Apr 03, 2025 am 12:03 AM

Apakah kaedah sihir PHP? Kaedah sihir PHP termasuk: 1. \ _ \ _ Membina, digunakan untuk memulakan objek; 2. \ _ \ _ Destruct, digunakan untuk membersihkan sumber; 3. \ _ \ _ Call, mengendalikan panggilan kaedah yang tidak wujud; 4. \ _ \ _ Mendapatkan, melaksanakan akses atribut dinamik; 5. \ _ \ _ Set, melaksanakan tetapan atribut dinamik. Kaedah ini secara automatik dipanggil dalam situasi tertentu, meningkatkan fleksibiliti dan kecekapan kod.

See all articles