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

news/2024/7/4 0:46:58 标签: php, zend, class, function, inheritance, interface
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。

博客地址:PHP技术博客 在CSDN也会同步更新的哦.

欢迎转载,转载请注明出处

这几天比较忙哦..没有时间写..周末了多写几篇吧.

目前大部分语言都支持类.
类是什么?类就是面向对象,简称OOP.英文名字 Object Oriented Programming.
面向对象是什么?是一种编程架构.
OOP的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成,OOP达到了软件工程的三个目标:重用性、灵活性和扩展性.
因为我们讲的不是这里只简单描述,如果你还不知道什么是类,什么是面向对象..那么这篇文章目前不适合你哦.
[class="tags" href="/tags/PHP.html" title=php>php]
class Person{


};
[/class="tags" href="/tags/PHP.html" title=php>php]
上面是创建一个PHP类.class是PHP的关键字.通过它我们就能找到Zend是如何创建类的.
class="language-cpp">unticked_class_declaration_statement:
                class_entry_type T_STRING extends_from
                        { class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
                        implements_list
                        '{'
                                class_statement_list
                        '}' { class="tags" href="/tags/ZEND.html" title=zend>zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
        |       interface_entry T_STRING
                        { class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
                        interface_extends_list
                        '{'
                                class_statement_list
                        '}' { class="tags" href="/tags/ZEND.html" title=zend>zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
;
class_entry_type:
                T_CLASS                 { $$.u.opline_num = CG(class="tags" href="/tags/ZEND.html" title=zend>zend_lineno); $$.u.EA.type = 0; } 
        |       T_ABSTRACT T_CLASS { $$.u.opline_num = CG(class="tags" href="/tags/ZEND.html" title=zend>zend_lineno); $$.u.EA.type = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
        |       T_FINAL T_CLASS { $$.u.opline_num = CG(class="tags" href="/tags/ZEND.html" title=zend>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/class="tags" href="/tags/ZEND.html" title=zend>zend_complie.h的文件中
class="language-cpp">#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 //接口





这三个规则 记录当前行,并设置类的类型.
在定义类的时候调用了 class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration和class="tags" href="/tags/ZEND.html" title=zend>zend_do_end_class_declaration两个方法,
类的关键字 ,类的名称和所继承的父类作为参数传递给这两个函数.
class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration是用来声明类,设置类型,创建一个
class="tags" href="/tags/ZEND.html" title=zend>zend_do_end_class_declaration用来处理类中的属性及方法.
在讲到两个函数之前一定先要说说 保存类的结构class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry
它定义在Zend/class="tags" href="/tags/ZEND.html" title=zend>zend.h中
class="language-cpp">struct _class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry {
        char type;
        char *name;//类名称
        class="tags" href="/tags/ZEND.html" title=zend>zend_uint name_length;
        struct _class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *parent; //所继承的父类
        int refcount;  //引用数
        class="tags" href="/tags/ZEND.html" title=zend>zend_bool constants_updated; //类的类型
        class="tags" href="/tags/ZEND.html" title=zend>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;
        const struct _class="tags" href="/tags/ZEND.html" title=zend>zend_function_entry *builtin_functions;
       //眼熟吗???对的.魔术函数在这里哦..
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *constructor;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *destructor;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *clone;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__get;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__set;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__unset;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__isset;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__call;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__callstatic;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *__tostring;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *serialize_func;
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *unserialize_func;


        class="tags" href="/tags/ZEND.html" title=zend>zend_class_iterator_funcs iterator_funcs;


        /* handlers */
        class="tags" href="/tags/ZEND.html" title=zend>zend_object_value (*create_object)(class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *class_type TSRMLS_DC);
        class="tags" href="/tags/ZEND.html" title=zend>zend_object_iterator *(*get_iterator)(class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
        int (*interface_gets_implemented)(class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *iface, class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
        union _class="tags" href="/tags/ZEND.html" title=zend>zend_function *(*get_static_method)(class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *ce, char* method, int method_len TSRMLS_DC);


        /* serializer callbacks */
        int (*serialize)(zval *object, unsigned char **buffer, class="tags" href="/tags/ZEND.html" title=zend>zend_uint *buf_len, class="tags" href="/tags/ZEND.html" title=zend>zend_serialize_data *data TSRMLS_DC);
        int (*unserialize)(zval **object, class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *ce, const unsigned char *buf, class="tags" href="/tags/ZEND.html" title=zend>zend_uint buf_len, class="tags" href="/tags/ZEND.html" title=zend>zend_unserialize_data *data TSRMLS_DC);


        class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry **interfaces;
        class="tags" href="/tags/ZEND.html" title=zend>zend_uint num_interfaces;


        char *filename;//声明类的文件地址
        class="tags" href="/tags/ZEND.html" title=zend>zend_uint line_start;//类开始行
        class="tags" href="/tags/ZEND.html" title=zend>zend_uint line_end;//类结束行
        char *doc_comment;
        class="tags" href="/tags/ZEND.html" title=zend>zend_uint doc_comment_len;


        struct _class="tags" href="/tags/ZEND.html" title=zend>zend_module_entry *module;
};




清楚了这个结构之后 下面来看看class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration函数
class="language-cpp">void class="tags" href="/tags/ZEND.html" title=zend>zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */
{
        class="tags" href="/tags/ZEND.html" title=zend>zend_op *opline;
        int doing_inheritance = 0;
        class="tags" href="/tags/ZEND.html" title=zend>zend_class_entry *new_class_entry;
        char *lcname;
        int error = 0;
        zval **ns_name;
        
        if (CG(active_class_entry)) {
                class="tags" href="/tags/ZEND.html" title=zend>zend_error(E_COMPILE_ERROR, "Class declarations may not be nested");
                return;
        }


        lcname = class="tags" href="/tags/ZEND.html" title=zend>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);
                class="tags" href="/tags/ZEND.html" title=zend>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) &&
                        class="tags" href="/tags/ZEND.html" title=zend>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);
                class="tags" href="/tags/ZEND.html" title=zend>zend_do_build_namespace_name(&tmp, &tmp, class_name TSRMLS_CC);
                class_name = &tmp;
                efree(lcname);
                lcname = class="tags" href="/tags/ZEND.html" title=zend>zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant));
        }


        if (error) {
                char *tmp = class="tags" href="/tags/ZEND.html" title=zend>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))) {
                        class="tags" href="/tags/ZEND.html" title=zend>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(class="tags" href="/tags/ZEND.html" title=zend>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;


        class="tags" href="/tags/ZEND.html" title=zend>zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
        new_class_entry->filename = class="tags" href="/tags/ZEND.html" title=zend>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) {
                        case ZEND_FETCH_CLASS_SELF:
                                class="tags" href="/tags/ZEND.html" title=zend>zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved");
                                break;
                        case ZEND_FETCH_CLASS_PARENT:
                                class="tags" href="/tags/ZEND.html" title=zend>zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved");
                                break;
                        case ZEND_FETCH_CLASS_STATIC:
                                class="tags" href="/tags/ZEND.html" title=zend>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;


        class="tags" href="/tags/ZEND.html" title=zend>zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(class="tags" href="/tags/ZEND.html" title=zend>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 = class="tags" href="/tags/ZEND.html" title=zend>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);
                class="tags" href="/tags/ZEND.html" title=zend>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行 初始化保存类的结构
class="tags" href="/tags/ZEND.html" title=zend>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引擎会调用class="tags" href="/tags/ZEND.html" title=zend>zend_execute函数执行OP的中间代码ZEND_DECLARE_CLASS_SPEC_HANDLER
它定义在Zend/class="tags" href="/tags/ZEND.html" title=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
如果存在 则会添加成功
那么到这里类就创建成功了.
下一张节就要深入到 类内部了哦...

http://www.niftyadmin.cn/n/1790469.html

相关文章

企业搭建三站合一网站教程

互联网时代快速更迭,企业想要快速抢占互联网、移动互联网、微信端市场,则需要组建一个更加庞大的体系,这其中就搭建一个PC手机微信三站合一的网站。但传统建站系统,三站都是独立分开的,维护起来非常费时费力费神&#…

【数据库审计】旁路式与植入式数据库审计技术有何差别 ...

在日渐火热的数据库安全领域,数据库审计应该是应用最为广泛,用户接受度最高的产品了,没有之一。 本文将对目前数据库审计市场上的两类技术路线进行分析,从使用效果出发,浅析两者在各维度的审计效果上存在哪些差异&…

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

声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。 博客地址:PHP技术博客 在CSDN也会同步更新的哦. 欢迎转载,转载请注明出处 上一章讲到类的实现 这一篇要详细讲讲PHP类的成员属性及方法.上一篇中曾经介绍到zend…

用css解决table文字溢出控制td显示字数

场景: 最左边这栏我不行让他换行,怎么办呢? 下面是解决办法: [plain] view plaincopy table{ width:100px; table-layout:fixed;/* 只有定义了表格的布局算法为fixed,下面td的定义才能起作用。 */ } td…

----------List的使用方法----------

package cn.lijun.demo;import java.util.ArrayList;import java.util.List;/* 有序 索引 可以重复 */public class ListDemo { public static void main(String[] args) { fun3(); } //3 修改指定索引上的元素 返回值是 被修改前的元素 public stati…

原:PHP数组函数研究:is_null,is_object,is_array,is_string,is_resource等

声明:本文为斯人原创,全部为作者一一分析得之,有不对的地方望赐教。欢迎转载,转载请注明出处 。本文地址:http://imsiren.com/archives/516前面有一篇文章 讲的是 PHP内核源码分析:isset与 empty 但是好像忘记了一系列…

吉尔电子烟获1200万天使轮融资

3月21日消息,近日从自媒体电子烟资讯得知,吉尔电子烟已签署1200万天使轮融资协议。 据悉,本轮融资将主要用于供应链整合和渠道扩展。投资方为苏州一家电子烟配件工厂企业,该工厂主要为美国某巨头电子烟品牌生产烟弹配件。目前还没…

Git - revert详解

git revert 撤销 某次操作,此次操作之前和之后的commit和history都会保留,并且把这次撤销作为一次最新的提交 * git revert HEAD 撤销前一次 commit * git revert HEAD^ 撤销前前一次 commit * git revert xxxx…