67-クラスの構造と実装

8808 ワード

67-クラスの構造と実装
オブジェクト向けプログラミングでは、クラスとオブジェクトの周りでプログラミングを行います.ではPHP内部クラスはどのように実現されているのでしょうか.メモリのレイアウトとストレージはどのようなものですか?継承、パッケージング、マルチステートはどのように実現されていますか?
クラスの構造
まずクラスが何なのか見てみましょう.クラスはユーザー定義の抽象データ型であり、現実世界のいくつかの共通性のあるものの抽象である.オブジェクトのカテゴリとして理解できる場合もあります.クラスは、属性、方法、および自身のいくつかの性質など、多様なデータを格納する必要がある複合型の構造と見なすこともできる.
クラスと関数は類似しており,PHP内蔵およびPHP拡張はいずれも独自の内部クラスを実現することができ,ユーザがPHPコードを用いて定義することもできる.もちろん、私たちはコードを書くときに通常自分で定義します.
使用上、classキーワードを使用して定義し、後にクラス名を付けます.クラス名はPHP以外の予約字の名前であってもいいです.クラス名の後ろには、PHPでサポートされているデータ型として表現されるオブジェクトの状態の抽象であるクラスのエンティティを含む一対のカッコが付いています.オブジェクト自体も含まれています.通常、メンバー変数と呼ばれています.クラスのプロパティに加えて、クラスのエンティティには、オブジェクトの動作の抽象であり、操作名とその操作を実装する方法として表現されるクラスが持つ操作も含まれます.通常、メンバーメソッドまたはメンバー関数と呼ばれます.クラスの例のコードを見てください.
class ParentClass {
}

interface Ifce {
        public function iMethod();
}

final class Tipi extends ParentClass implements Ifce {
        public static $sa = 'aaa';
        const CA = 'bbb';

        public function __constrct() {
        }

        public function iMethod() {
        }

        private function _access() {
        }

        public static function access() {
        }
}

ここでは、親クラスParentClass、インタフェースIfce、サブクラスTipiを定義します.子クラスは親クラスParentClassを継承し、インタフェースIfceを実装し、静的変数$sa、クラス定数CA、共通メソッド、プライベートメソッド、共通静的メソッドがあります.これらの構造はZendエンジン内部でどのように実現されていますか?クラスのメソッド、メンバー変数はどのように格納されますか?アクセス制御、静的メンバーはどのようにマークされますか?
まず、クラスの内部ストレージ構造を見てみましょう.
struct _zend_class_entry {
    char type;     //   :ZEND_INTERNAL_CLASS / ZEND_USER_CLASS
    char *name;//    
    zend_uint name_length;                  //  sizeof(name) - 1
    struct _zend_class_entry *parent; //      
    int refcount;  //    
    zend_bool constants_updated;

    zend_uint ce_flags; // ZEND_ACC_IMPLICIT_ABSTRACT_CLASS:    abstract  
    // ZEND_ACC_EXPLICIT_ABSTRACT_CLASS:        abstract   
    // ZEND_ACC_FINAL_CLASS
    // ZEND_ACC_INTERFACE
    HashTable function_table;      //   
    HashTable default_properties;          //     
    HashTable properties_info;     //     
    HashTable default_static_members;//            
    HashTable *static_members; // type == ZEND_USER_CLASS , &default_static_members;
    // type == ZEND_INTERAL_CLASS ,  NULL
    HashTable constants_table;     //   
    struct _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 *__tostring;
    union _zend_function *serialize_func;
    union _zend_function *unserialize_func;
    zend_class_iterator_funcs iterator_funcs;//   

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


    /*           */
    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; //         :EG(current_module)
};

上記の構造の一部のフィールドを取って、文章の最初のPHPコードのカーネルでの表現を分析します.次の表に示します.
フィールド名
フィールドの説明
ParentClassクラス
Ifceインタフェース
Tipiクラス
name
クラス名
ParentClass Ifce
Tipi
type
カテゴリ
2
2
2
parent



ParentClassクラス
refcount
参照数
1
1
2
ce_flags
クラスのタイプ
0
144
524352
function_table
関数リスト

function_name=iMethod | type=2 | fn_flags=258
function_name=__construct | type=2 | fn_flags=8448 function_name=iMethod | type=2 | fn_flags=65800 function_name=_access | type=2 | fn_flags=66560 function_name=access | type=2 | fn_flags=257
interfaces
インタフェースリスト


Ifceインタフェース
インタフェース数1
filename
ファイルアドレスの保存
/tipi.php
/tipi.php
/ipi.php
line_start
クラス開始行数
15
18
22
line_end
クラス終了行数
16
20
38
クラスの構造ではtypeには2種類あり、数字は1と2と表記されています.マクロの定義は、ユーザー定義のクラスとモジュール、または内蔵のクラスもこの構造に保存されています.
#define ZEND_INTERNAL_CLASS         1
#define ZEND_USER_CLASS             2

親とインタフェースはstruct_に保存されます.zend_class_entry構造体.これは,インタフェースもクラス形式で格納され,実装は同様であり,継承などの操作時にクラス操作とは異なる処理があることを示す.従来のメンバーメソッドは関数構造体のハッシュテーブルに格納され、マジックメソッドは単独で保存されます.クラス定義のunion_のようにzend_function *constructor; 定義はクラスの構造マジックメソッドであり,関数としてクラス構造に存在し,従来のメソッドとは分離されている.初期化すると、これらのマジックメソッドはNULLに設定されます.
クラスの実装
クラスの定義はclassキーワードで始まり、Zend/zend_でlanguage_scanner.lファイルでclass対応tokenがT_CLASS. これにより、Zend/zend_language_parser.yファイルで、コンパイル時に呼び出される関数を見つけます.
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; }
;

上のclass_entry_type構文は、構文解析フェーズでクラスを通常クラス(T_CLASS)、抽象クラス(T_ABSTRACT T_CLASS)、finalクラス(T_FINAL T_CLASS)の3種類に分類することを示します.それぞれ対応するタイプは、カーネル内で次のとおりです.
  • 通常クラス(T_CLASS)対応type=0
  • 抽象クラス(T_ABSTRACT T_CLASS)対応type=ZEND_ACC_EXPLICIT_ABSTRACT_CLASS
  • finalクラス(T_FINAL T_CLASS)対応type=ZEND_ACC_FINAL_CLASS

  • 上記の3つのタイプに加えて、クラスにはabstractキーワードを付けていない抽象クラスとインタフェースの2つのタイプが含まれています.
  • abstractキーワードを付けていない抽象クラス、それに対応するtype=ZEND_ACC_IMPLICIT_ABSTRACT_CLASS. classの前にabstractキーワードがないため、構文解析では抽象クラスとして解析されていませんが、クラスに抽象メソッドがあるため、関数登録時にメンバー関数が抽象メソッドであるか継承クラスのメンバーメソッドが抽象メソッドであると判断した場合、このクラスをこの抽象クラスタイプに設定します.
  • インターフェース、そのtype=ZEND_ACC_INTERFACE.インタフェースタイプの区分はinterfaceキーワード解析時に設定されます.interface_を参照してください.entry:対応する文法の説明.

  • この5種類はZend/zend_complie.hファイルには以下のように定義されている.
    #define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10
    #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS    0x20
    #define ZEND_ACC_FINAL_CLASS                0x40
    #define ZEND_ACC_INTERFACE                  0x80
    

    通常クラスは0であり、ここでは定義されず、プログラムでも直接0に割り当てられます.
    構文解析が完了すると、抽象クラスなのかfinalクラスなのか、普通のクラスなのか、インタフェースなのかがわかります.クラスの定義時にzend_が呼び出されましたdo_begin_class_declarationとzend_do_end_class_declaration関数、この2つの関数から入力されたパラメータ、zend_do_begin_class_declaration関数はクラス名、クラスのカテゴリ、親クラスを処理するために使用されます.zend_do_end_class_declaration関数インタフェースとクラスの中間コードを処理するための2つの関数はZend/zend_complie.cファイルには、その実装が見つかります.
    zend_でdo_begin_class_declarationでは、まず、伝達されたクラスの名作を小文字に変換します.これも、クラス名がサイズを区別しない理由です.次のコードです.
    <?php
    class TIPI {
    }
    
    class tipi {
    
    }
    ?>
    

    ランタイムプログラムエラー:Fatal error:Cannot redeclare class tipi.このエラーは、生成中のコードを実行するときにトリガーされます.このエラーの判定手順は、後述する中間コード生成時に説明する.クラス名の判断はT_STRING tokenは,構文解析時に行う判断であるが,クラス名が文字列であることしか認識できない.クラス名がキーワードの場合、次のコードがあります.
    class self {
    }
    

    実行すると、Fatal error:Cannot use'self'as class name as it is reserved in...
    以上のエラープログラム判定定義はzend_do_begin_class_declaration関数.selfキーワードと同様にparent,staticの2つのキーワードの判断は同じ場所にある.この関数が実行されると、クラス宣言で生成された中間コードはZEND_となります.DECLARE_CLASS . もちろん、内部クラスを宣言する場合、生成される中間コードは:ZEND_DECLARE_INHERITED_CLASS.
    生成された中間コードに基づいてZend/zend_vm_execute.hファイルに対応する実行関数ZEND_が見つかりましたDECLARE_CLASS_SPEC_HANDLER. この関数はdo_を呼び出すことによってbind_class関数はこれをEG(class_table)に追加します.リストに追加すると同時に、クラスが存在するかどうかも判断し、存在する場合は追加に失敗し、前に述べたクラスの繰り返し宣言エラーを報告しますが、この判断はコンパイルがオンのときには有効ではありません.
    クラス関連の各構造はstruct_に保存されます.zend_class_entry構造体.これらの具体的なカテゴリは文法分析の過程で区別される.クラスのカテゴリ,クラスのクラス名などを識別し,識別した結果をクラスの構造に格納する.