深刻明PHP内核(十三)类的构造及促成

初稿链接:http://www.orlion.ga/1117/

先押一下类之布局:

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)
};

    类的构造被,type有三三两两种类型,数字符号为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。根据此token,在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)。他们各自对应的色在根本中吗:

  • 常规类(T_CLASS)对应的type=0

  • 抽象类(T_ABSTRACT
    T_CLASS)对应type=ZEND_ACC_EXPLICIT_ABSTRACT_CLASS

  • final类(T_FINAL T_CLASS)对应type=ZEND_ACC_FINAL_CLASS

    除了上面三栽档次外,类还有另外两种类型没有加abstract关键字的抽象类和接口:

  • 没加abstract关键字的抽象类,它对应之type=ZEND_ACC_IMPLICIT_ABSTRACT_CLASS。由于并未在class前面没有abstract关键字,在语法分析时并没分析出马上是一个抽象类,但是由类中尚无抽象方法,在函数注册时判断成员函数是空虚方法或者继承类中之分子方法是空泛方法,会用以此仿佛设置也夫种植浮泛类型。

  • 接口,其type=ZEND_ACC_INTERFACE。接口类型的区别是以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
#define ZEND_ACC_INTERFACE                  0x80

    常规类为0。语法解析了晚就知晓一个好像是抽象类还是final类、普通的类似、接口。定义类时调用了zend_do_begin_class_declaration和zend_do_end_class_declaration函数,从这简单只函数传入的参数,zend_do_begin_class_declaration函数用来处理类名,类的路和父类,zend_do_end_class_declaration函数用来处理接口及类似的中间代码,这简单独函数在Zend/zend_complie.c文件中可以寻找到那个实现。

    在zend_do_begin_class_declaration中,首先会见指向传播的类名做一个转化,统一改为小写(这为是类名不分轻重缓急写的缘由)。

    
    类名重复(如定义了区区单Person类)错误的论断过程在中间代码生成时,关于类名的判断是通过T_STRING
token,在语法解析时举行的判断,但是就不得不识别出类名是一个字符串。假如类名为一些至关重要字而声明class
self会报错,这个错误的判定定义在zend_do_begin_class_declaration函数,与self关键字一样,还有parent,static两个基本点字之论断在和一个地方。当这函数执行了晚,我们见面沾近似声明生成的中间代码为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结构体中,这些实际的品类在语法分析过程中开展分。识别出类的门类,类的类名等,并以识别出来的结果存放到类的组织中。

相关文章