zoukankan      html  css  js  c++  java
  • php 类继承

    %token T_EXTENDS    "extends (T_EXTENDS)"
    
    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, &$3 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, NULL TSRMLS_CC); }
    ;
    
    extends_from:
            /* empty */                    { $$.op_type = IS_UNUSED; }
        |    T_EXTENDS fully_qualified_class_name    { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); }
    ;
    
    
    implements_list:
            /* empty */
        |    T_IMPLEMENTS interface_list
    ;
    
    interface_list:
            fully_qualified_class_name            { zend_do_implements_interface(&$1 TSRMLS_CC); }
        |    interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
    ;
    
    fully_qualified_class_name:
            namespace_name { $$ = $1; }
        
    ;
    
    namespace_name:
            T_STRING { $$ = $1; }
        |    namespace_name T_NS_SEPARATOR T_STRING { zend_do_build_namespace_name(&$$, &$1, &$3 TSRMLS_CC); }
    ;

     

     2. 针对extends 的函数 zend_do_fetch_class

    void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
    {
        long fetch_class_op_number;
        zend_op *opline;
    
        if (class_name->op_type == IS_CONST &&
            Z_TYPE(class_name->u.constant) == IS_STRING &&
            Z_STRLEN(class_name->u.constant) == 0) {
            /* Usage of namespace as class name not in namespace */
            zval_dtor(&class_name->u.constant);
            zend_error(E_COMPILE_ERROR, "Cannot use 'namespace' as a class name");
            return;
        }
    
        fetch_class_op_number = get_next_op_number(CG(active_op_array));
        opline = get_next_op(CG(active_op_array) TSRMLS_CC);
    
        opline->opcode = ZEND_FETCH_CLASS;
        SET_UNUSED(opline->op1);
        opline->extended_value = ZEND_FETCH_CLASS_GLOBAL;
        CG(catch_begin) = fetch_class_op_number;
        if (class_name->op_type == IS_CONST) {
            int fetch_type;
    
            fetch_type = zend_get_class_fetch_type(class_name->u.constant.value.str.val, class_name->u.constant.value.str.len);
            switch (fetch_type) {
                case ZEND_FETCH_CLASS_SELF:
                case ZEND_FETCH_CLASS_PARENT:
                case ZEND_FETCH_CLASS_STATIC:
                    SET_UNUSED(opline->op2);
                    opline->extended_value = fetch_type;
                    zval_dtor(&class_name->u.constant);
                    break;
                default:
                    zend_resolve_class_name(class_name, opline->extended_value, 0 TSRMLS_CC);
                    opline->op2_type = IS_CONST;
                    opline->op2.constant =
                        zend_add_class_name_literal(CG(active_op_array), &class_name->u.constant TSRMLS_CC);
                    break;
            }
        } else {
            SET_NODE(opline->op2, class_name);
        }
        opline->result.var = get_temporary_variable(CG(active_op_array));
        opline->result_type = IS_VAR; /* FIXME: Hack so that INIT_FCALL_BY_NAME still knows this is a class */
        GET_NODE(result, opline->result);
        result->EA = opline->extended_value;
    }

    3.ZEND_FETCH_CLASS_SPEC_CONST_HANDLER函数

    static int ZEND_FASTCALL  ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
    
        SAVE_OPLINE();
        EG(exception) = NULL;
        if (IS_CONST == IS_UNUSED) {
            //omit
        } else {
    
            zval *class_name = opline->op2.zv;
    
            if (IS_CONST == IS_CONST) {
                if (CACHED_PTR(opline->op2.literal->cache_slot)) {
                    EX_T(opline->result.var).class_entry = CACHED_PTR(opline->op2.literal->cache_slot);
                } else {
                    EX_T(opline->result.var).class_entry = zend_fetch_class_by_name(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->op2.literal + 1, opline->extended_value TSRMLS_CC);
                    CACHE_PTR(opline->op2.literal->cache_slot, EX_T(opline->result.var).class_entry);
                }
            } else if (Z_TYPE_P(class_name) == IS_OBJECT) {
                EX_T(opline->result.var).class_entry = Z_OBJCE_P(class_name);
            } else if (Z_TYPE_P(class_name) == IS_STRING) {
                EX_T(opline->result.var).class_entry = zend_fetch_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), opline->extended_value TSRMLS_CC);
            } else {
                zend_error_noreturn(E_ERROR, "Class name must be a valid object or a string");
            }
    
            CHECK_EXCEPTION();
            ZEND_VM_NEXT_OPCODE();
        }
    }

    4.zend_fetch_class_by_name函数

    zend_class_entry *zend_fetch_class_by_name(const char *class_name, uint class_name_len, const zend_literal *key, int fetch_type TSRMLS_DC) /* {{{ */
    {
        zend_class_entry **pce;
        int use_autoload = (fetch_type & ZEND_FETCH_CLASS_NO_AUTOLOAD) == 0;
    
        if (zend_lookup_class_ex(class_name, class_name_len, key, use_autoload, &pce TSRMLS_CC) == FAILURE) {
            if (use_autoload) {
                if ((fetch_type & ZEND_FETCH_CLASS_SILENT) == 0 && !EG(exception)) {
                    if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_INTERFACE) {
                        zend_error(E_ERROR, "Interface '%s' not found", class_name);
                    } else if ((fetch_type & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_TRAIT) {
                        zend_error(E_ERROR, "Trait '%s' not found", class_name);
                    } else {
                        zend_error(E_ERROR, "Class '%s' not found", class_name);
                    }    
                }
            }
            return NULL;
        }
        return *pce;
    }
    
    
    ZEND_API int zend_lookup_class(const char *name, int name_length, zend_class_entry ***ce TSRMLS_DC) /* {{{ */
    {
        return zend_lookup_class_ex(name, name_length, NULL, 1, ce TSRMLS_CC);
    }
    
    
    ZEND_API int zend_lookup_class_ex(const char *name, int name_length, const zend_literal *key, int use_autoload, zend_class_entry ***ce TSRMLS_DC) /* {{{ */
    {
        zval **args[1];
        zval autoload_function;
        zval *class_name_ptr;
        zval *retval_ptr = NULL;
        int retval, lc_length;
        char *lc_name;
        char *lc_free;
        zend_fcall_info fcall_info;
        zend_fcall_info_cache fcall_cache;
        char dummy = 1;
        ulong hash;
        ALLOCA_FLAG(use_heap)
    
        if (key) {
            lc_name = Z_STRVAL(key->constant);
            lc_length = Z_STRLEN(key->constant) + 1;
            hash = key->hash_value;
        } else {
            if (name == NULL || !name_length) {
                return FAILURE;
            }
    
            lc_free = lc_name = do_alloca(name_length + 1, use_heap);
            zend_str_tolower_copy(lc_name, name, name_length);
            lc_length = name_length + 1;
    
            if (lc_name[0] == '\') {
                lc_name += 1;
                lc_length -= 1;
            }
    
            hash = zend_inline_hash_func(lc_name, lc_length);
        }
    
        if (zend_hash_quick_find(EG(class_table), lc_name, lc_length, hash, (void **) ce) == SUCCESS) {
            if (!key) {
                free_alloca(lc_free, use_heap);
            }
            return SUCCESS;
        }
        //omit
    }

     开始声明类

    void zend_do_begin_class_declaration(const znode *class_token, znode *class_name, const znode *parent_class_name TSRMLS_DC) /* {{{ */
    {
        zend_op *opline;
        int doing_inheritance = 0;
        zend_class_entry *new_class_entry;
        char *lcname;
        int error = 0;
        zval **ns_name, key;
    
        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);
       //不允许 类名为 self ,也不允许类名为parent
    if (!(strcmp(lcname, "self") && strcmp(lcname, "parent"))) { efree(lcname); zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", Z_STRVAL(class_name->u.constant)); } /* 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.op_type = IS_CONST; 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); }
    //开始为zend_class_entry分配内存,并设置相应属性 new_class_entry
    = emalloc(sizeof(zend_class_entry)); new_class_entry->type = ZEND_USER_CLASS; new_class_entry->name = zend_new_interned_string(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant) + 1, 1 TSRMLS_CC); new_class_entry->name_length = Z_STRLEN(class_name->u.constant);
      //初始化一些数据 zend_initialize_class_data(new_class_entry,
    1 TSRMLS_CC);

      //设置文件名称,以及开始行号,以及该类的类型 new_class_entry
    ->info.user.filename = zend_get_compiled_filename(TSRMLS_C); new_class_entry->info.user.line_start = class_token->u.op.opline_num; new_class_entry->ce_flags |= class_token->EA; if (parent_class_name && parent_class_name->op_type != IS_UNUSED) { switch (parent_class_name->EA) { case ZEND_FETCH_CLASS_SELF: zend_error(E_COMPILE_ERROR, "Cannot use 'self' as class name as it is reserved"); break; case ZEND_FETCH_CLASS_PARENT: zend_error(E_COMPILE_ERROR, "Cannot use 'parent' as class name as it is reserved"); break; case ZEND_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 opline
    = get_next_op(CG(active_op_array) TSRMLS_CC); opline->op1_type = IS_CONST; build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);

      //op1.constant为key,类名已经放至了CG(active_op_array)中的zend_literal,zend_literal是个结构体数组 opline
    ->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC); Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant))); opline->op2_type = IS_CONST; if (doing_inheritance) { /* Make sure a trait does not try to extend a class */ if ((new_class_entry->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { zend_error(E_COMPILE_ERROR, "A trait (%s) cannot extend a class. Traits can only be composed from other traits with the 'use' keyword. Error", new_class_entry->name); } opline->extended_value = parent_class_name->u.op.var;  

         //开始继承类 opline
    ->opcode = ZEND_DECLARE_INHERITED_CLASS; } else { opline->opcode = ZEND_DECLARE_CLASS; } LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0); CALCULATE_LITERAL_HASH(opline->op2.constant); zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL); CG(active_class_entry) = new_class_entry; opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; GET_NODE(&CG(implementing_class), opline->result); if (CG(doc_comment)) { CG(active_class_entry)->info.user.doc_comment = CG(doc_comment); CG(active_class_entry)->info.user.doc_comment_len = CG(doc_comment_len); CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } }

     

    static int ZEND_FASTCALL  ZEND_DECLARE_INHERITED_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
    
        SAVE_OPLINE();
        EX_T(opline->result.var).class_entry = do_bind_inherited_class(EX(op_array), opline, EG(class_table), EX_T(opline->extended_value).class_entry, 0 TSRMLS_CC);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }

     绑定父类

    ZEND_API zend_class_entry *do_bind_inherited_class(const zend_op_array *op_array, const zend_op *opline, HashTable *class_table, zend_class_entry *parent_ce, zend_bool compile_time TSRMLS_DC) /* {{{ */
    {
        zend_class_entry *ce, **pce;
        int found_ce;
        zval *op1, *op2;
    
        if (compile_time) {
            op1 = &CONSTANT_EX(op_array, opline->op1.constant);
            op2 = &CONSTANT_EX(op_array, opline->op2.constant);
        } else {
            op1 = opline->op1.zv;
            op2 = opline->op2.zv;
        }
    
        found_ce = zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce);
    
        if (found_ce == FAILURE) {
            if (!compile_time) {
                /* If we're in compile time, in practice, it's quite possible
                 * that we'll never reach this class declaration at runtime,
                 * so we shut up about it.  This allows the if (!defined('FOO')) { return; }
                 * approach to work.
                 */
                zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", Z_STRVAL_P(op2));
            }
            return NULL;
        } else {
            ce = *pce;
        }
        
      
       //如果父类 类型是 接口,或者是trait,均不能继承
    if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) { zend_error(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ce->name, parent_ce->name); } else if ((parent_ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { zend_error(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ce->name, parent_ce->name); } zend_do_inheritance(ce, parent_ce TSRMLS_CC); ce->refcount++; /* Register the derived class */ if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), pce, sizeof(zend_class_entry *), NULL)==FAILURE) { zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", ce->name); } return ce; }
    ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
    {
        zend_property_info *property_info;
    
        if ((ce->ce_flags & ZEND_ACC_INTERFACE)
            && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
            zend_error(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
        }
        if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
            zend_error(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name, parent_ce->name);
        }
     
       //设置ce的父类 ce
    ->parent = parent_ce; /* Copy serialize/unserialize callbacks */ if (!ce->serialize) { ce->serialize = parent_ce->serialize; } if (!ce->unserialize) { ce->unserialize = parent_ce->unserialize; } /* Inherit interfaces */ zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC); /* Inherit properties */

    //继承 父类的属性 if (parent_ce->default_properties_count) { int i = ce->default_properties_count + parent_ce->default_properties_count; ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); if (ce->default_properties_count) { while (i-- > parent_ce->default_properties_count) { ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count]; } } for (i = 0; i < parent_ce->default_properties_count; i++) { ce->default_properties_table[i] = parent_ce->default_properties_table[i]; if (ce->default_properties_table[i]) { #ifdef ZTS if (parent_ce->type != ce->type) { zval *p; ALLOC_ZVAL(p); MAKE_COPY_ZVAL(&ce->default_properties_table[i], p); ce->default_properties_table[i] = p; } else { Z_ADDREF_P(ce->default_properties_table[i]); } #else Z_ADDREF_P(ce->default_properties_table[i]); #endif } } ce->default_properties_count += parent_ce->default_properties_count; } if (parent_ce->type != ce->type) { /* User class extends internal class */ zend_update_class_constants(parent_ce TSRMLS_CC); if (parent_ce->default_static_members_count) { int i = ce->default_static_members_count + parent_ce->default_static_members_count; ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(void*) * i); if (ce->default_static_members_count) { while (i-- > parent_ce->default_static_members_count) { ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; } } for (i = 0; i < parent_ce->default_static_members_count; i++) { SEPARATE_ZVAL_TO_MAKE_IS_REF(&CE_STATIC_MEMBERS(parent_ce)[i]); ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i]; Z_ADDREF_P(ce->default_static_members_table[i]); } ce->default_static_members_count += parent_ce->default_static_members_count; ce->static_members_table = ce->default_static_members_table; } } else { if (parent_ce->default_static_members_count) { int i = ce->default_static_members_count + parent_ce->default_static_members_count; ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(void*) * i, ce->type == ZEND_INTERNAL_CLASS); if (ce->default_static_members_count) { while (i-- > parent_ce->default_static_members_count) { ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count]; } } for (i = 0; i < parent_ce->default_static_members_count; i++) { SEPARATE_ZVAL_TO_MAKE_IS_REF(&parent_ce->default_static_members_table[i]); ce->default_static_members_table[i] = parent_ce->default_static_members_table[i]; Z_ADDREF_P(ce->default_static_members_table[i]); } ce->default_static_members_count += parent_ce->default_static_members_count; if (ce->type == ZEND_USER_CLASS) { ce->static_members_table = ce->default_static_members_table; } } } for (zend_hash_internal_pointer_reset(&ce->properties_info); zend_hash_get_current_data(&ce->properties_info, (void *) &property_info) == SUCCESS; zend_hash_move_forward(&ce->properties_info)) { if (property_info->ce == ce) { if (property_info->flags & ZEND_ACC_STATIC) { property_info->offset += parent_ce->default_static_members_count; } else { property_info->offset += parent_ce->default_properties_count; } } } zend_hash_merge_ex(&ce->properties_info, &parent_ce->properties_info, (copy_ctor_func_t) (ce->type & ZEND_INTERNAL_CLASS ? zend_duplicate_property_info_internal : zend_duplicate_property_info), sizeof(zend_property_info), (merge_checker_func_t) do_inherit_property_access_check, ce); zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, zval_property_ctor(parent_ce, ce), NULL, sizeof(zval *), 0); zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce); do_inherit_parent_constructor(ce); if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) { ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) { /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */ zend_verify_abstract_class(ce TSRMLS_CC); } ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS; }

     

  • 相关阅读:
    一个人事工资模块
    Delete From 带 inner join
    打开SQL AnyWhere *.db数据库
    开启查询IO操作统计
    一个大数据量表访问优化联动下拉框查询优化
    一个简单的配置文件读取类
    MSSQL2005 双机热备说明
    数据库镜像
    GridView + ObjectDatasource 的一个范例代码
    往带自增长列的数据表中导数据
  • 原文地址:https://www.cnblogs.com/taek/p/4133890.html
Copyright © 2011-2022 走看看