首頁  >  文章  >  後端開發  >  原創:PHP核心研究之類的實現

原創:PHP核心研究之類的實現

黄舟
黄舟原創
2016-12-22 09:56:421159瀏覽

這幾天比較忙哦..沒有時間寫..週末了多寫幾篇吧.
目前大部分語言都支持類.
類是什麼?類就是面向對象,簡稱OOP.英文名字Object Oriented Programming.
物件導向是什麼?是一種程式設計架構.
OOP的一條基本原則是電腦程式是由單一能夠起到子程式作用的單元或物件組合而成,OOP達到了軟體工程的三個目標:重用性、靈活性和擴展性.
因為我們講的不是這裡只簡單描述,如果你還不知道什麼是類,什麼是面向對象..那麼這篇文章目前不適合你哦.

classPerson{

  

};

   

上面是創建一個PHP類.class是PHP的關鍵字.透過它我們就能找到Zend是如何被創建類的.

state:cg             class_entry_type T_STRING extends_from

                        { zend_do_begin_class_declaration (             implements_list

                                      class_statement_list

         $1, &$2 TSRMLS_CC); }

        |       interface_entry T_STRING

                        { zend_do_begin_class_declaration()             interface_extends_list

                                     地_statement_list

       (&$1, &$2 TSRMLS_CC); }

;

class_entry_type :

                T_CLASS                      |       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(CLf.R.com);

   

T_CLASS, T_ABSTRACT T_CLASS和T_FINAL 是PHP的三種類的模式

T_CLASS:是一個標準類.

T_ABSTRACT:是聲明一個抽象類

T_FINAL:聲明一個不容忍繼承和擴展的類.

當然還有interface

/zend_complie.h的文件中

   

#define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10    //沒有聲明為抽象化,但是內部有抽象方法抽象

#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 {

            zend_uint name_length;

        struct_zend_class_entry *parent;//所繼承的父類別

intrefcount; //引用數

        zend_bool constants_updated;//類別的型別

        HashTable function_table; //函數表

        HashTable default_properties;//屬性

        HashTable properties_info; //函數的存取等級

        HashTable default_static_members;//L 宣告的類別等於default_static_members,內建的類別為NULL

        HashTable constants_table;

        conststruct_zend_function_entry *builtin_functions;

       //眼眶

        union_zend_function *destructor;

        union_zend_function union_zend_function *__set;

        union_zend_function *__unset;

       *__call;

        union_zend_function *__callstatic;

        union_zend_function *__string; ;

        union_zend_function *unserialize_func;

  

zend_class_iterator_funcs iterator_funcs;

  

        /* handlers */

  DC);

        zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object,intby  (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC);/* a class implements this interface */

    _len TSRMLS_DC);

  

        / * serializer callbacks */

        int(*serialize)(zval *object, unsignedchar**buffer, zend_uint *buf_len, zend_serialize_數據**object, zend_class_entry *ce,constunsignedchar *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);

  

        zend_class_entry **interfaces🠎faces🠎face 

  

        char*filename;//聲明類別的檔案位址

        zend_uint line_start;//類別開始行程

        zend_uint line_end;///類別結束行程

        char* 

  

        struct_zend_module_entry *module;

};

   

🜠

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;

        intererror = 0;

        zval **ns_name;

  

        if( CG(active_class_entry)) {

                zend_error(E_COMPILE_ERROR,"類別聲明

        }

  

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

  

        if(!(strcmp(lcname,"self") &&strcmp  efree(lcname);

                zend_error (E_COMPILE_ERROR,"不能使用'%s' 作為類別名,因為它是保留的", class_name->u.constant.value.str.val);

        名稱衝突*/

        if(CG(current_import) &&

             class_name->u.constant)+1, (void**)&ns_name) == SUCCESS) {

error = 1;

        }

       if(CG(current_namespace)) {    

                znode tmp;

  

    current_namespace);

                zval_copy_ctor(&tmp.u.constant);

&tmp, class_name TSRMLS_CC);

                class_name = &tmp;

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

        }

  

🎠        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))PP(ns_name) !=         memcmp(tmp, lcname, Z_STRLEN (class_name->u.constant))) {

                        zend_error(E_COMPILE_ERROR,"無法聲明          }

       }

       } }

        new_entry = emalloc(sizeof(zend_class_entry));

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

        new_class_entry ->名稱長度=類別名稱->u.constant.value.str.len;

  

        zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); 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-name-Ftype!         switch(parent_class_name ->u.EA .type) {

                        caseZEND_FETCH_CLASS         zend_error(E_COMPILE_ERROR,"不能使用'self'作為類別名,因為它是保留的");

                                ;

                       caseZEND_FETCH_CLASS_PARENT:

                                zend_error(E_COMPILE_ERROR,"不能使用“父級”作為保留的類名");

                                break;

                       caseZEND_FETCH_CLASS_STATIC:

                                 zend_error(E_COMPILE_ERROR,"不能使用 'static' 作為類名,因為它是保留的");

                                 預設:

;

                 } 

        }

  

        opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->op1.op_type = IS_CONST;

        build_runtime_define_function_key(&opline->op1 .u.constant, lcname, new_class_key(&opline->op1 .u.constant, lcname, new_class_entry-TSname_length 起

        opline->op2.op_type = IS_CONST;

        opline->op2.u.為一篇constant, 1);

  

        如果(do_inheritance) {

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

  CLASS;

        }else {

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

        opline->op2.u.constant.value.str.len = new_class_entry->name_length; ) ), opline->op1.u. Constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry,sizeof(zend_class_entry *), NULL);

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

opline-> result.op_type = is_var;

cg;

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

               CG(active_class_entry) ->doc_comment_len = (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);

把所有類別全部寫成小寫處理。不敏感的原因。類別名,因為它是保留的”, class_name->u.constant.value.str.val);

}

類別的名字不能是self和parent。

第23-26行用來偵測類別名稱是否重複定義。 new_class_entry, 1 TSRMLS_CC);函數是用來初始化結構裡面的HashTable,魔術方法。為NULL)的原因

第58-73行同樣用於檢測父類的類名是否包含保留關鍵字self,parent,static

剩下的就是用來生成一個OP,

是內部類:那么生成的OP中間程式碼就是ZEND_DECLARE_INHERITED_CLASS

是用戶類別:OP中間程式碼就是ZEND_DECLARE_CLASS

在此之後..Zend引擎會呼叫zend_execute函數執行OP中間的程式碼ZEND_DECLARE_CLASS_SPEC_HANERER

它將這個關鍵程式碼。

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