zoukankan      html  css  js  c++  java
  • php类的实现

    zend_class_entry

    typedef struct _zend_class_entry zend_class_entry;
    
    struct _zend_class_entry {
        char type;
        char *name;
        zend_uint name_length;
        struct _zend_class_entry *parent;
        int refcount;
        zend_bool constants_updated;
        zend_uint ce_flags;
    
        HashTable function_table;
        HashTable default_properties;
        HashTable properties_info;
        HashTable default_static_members;
        HashTable *static_members;
        HashTable constants_table;
        const 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 *__callstatic;
        union _zend_function *__tostring;
        union _zend_function *serialize_func;
        union _zend_function *unserialize_func;
    
        zend_class_iterator_funcs iterator_funcs;
    
        /* handlers */
        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
        zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
        int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
        union _zend_function *(*get_static_method)(zend_class_entry *ce, char* method, int method_len TSRMLS_DC);
    
        /* serializer callbacks */
        int (*serialize)(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
        int (*unserialize)(zval **object, zend_class_entry *ce, const unsigned char *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;
    };

    typedef struct _zend_property_info {
    zend_uint flags;
    char *name;
    int name_length;
    ulong h;
    char *doc_comment;
    int doc_comment_len;
    zend_class_entry *ce;
    } zend_property_info;

    1.BNF范式(语法规则)

    %token T_PAAMAYIM_NEKUDOTAYIM ":: (T_PAAMAYIM_NEKUDOTAYIM)"
    %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); }
    ;
    

    //类的修饰符

    class_entry_type:
            T_CLASS            { $$.u.op.opline_num = CG(zend_lineno); $$.EA = 0; }
        |    T_ABSTRACT T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
        |    T_TRAIT { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_TRAIT; }
        |    T_FINAL T_CLASS { $$.u.op.opline_num = CG(zend_lineno); $$.EA = ZEND_ACC_FINAL_CLASS; }
    ;

    extends_from:
            /* empty */                    { $$.op_type = IS_UNUSED; }
        |    T_EXTENDS fully_qualified_class_name    { zend_do_fetch_class(&$$, &$2 TSRMLS_CC); }
    ;

    
    class_statement_list:
            class_statement_list class_statement
        |    /* empty */
    ;
    
    class_statement:
            variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';' //定义成员变量
        |    class_constant_declaration ';'
        |    trait_use_statement
        |    method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '('
                parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); } //定义成员方法
    ;
    
    variable_modifiers:
            non_empty_member_modifiers        { $$ = $1; }
        |    T_VAR                            { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
      ;
    method_modifiers:
       /* empty */                            { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
       |    non_empty_member_modifiers            { $$ = $1;  if (!(Z_LVAL($$.u.constant) & ZEND_ACC_PPP_MASK)) { Z_LVAL($$.u.constant) |= ZEND_ACC_PUBLIC; } }
    ;
    
    
    

     non_empty_member_modifiers:
      member_modifier { $$ = $1; }
      | non_empty_member_modifiers member_modifier { Z_LVAL($$.u.constant) = zend_do_verify_access_types(&$1, &$2); }
    ;

     member_modifier: //成员修饰符,用于成员变量以及成员方法
       T_PUBLIC { Z_LVAL($$.u.constant) = ZEND_ACC_PUBLIC; }
      | T_PROTECTED { Z_LVAL($$.u.constant) = ZEND_ACC_PROTECTED; }
      | T_PRIVATE { Z_LVAL($$.u.constant) = ZEND_ACC_PRIVATE; }
      | T_STATIC { Z_LVAL($$.u.constant) = ZEND_ACC_STATIC; }
      | T_ABSTRACT { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
      | T_FINAL { Z_LVAL($$.u.constant) = ZEND_ACC_FINAL; }
    ;



    method_body: //方法体
    ';' /* abstract method */        { Z_LVAL($$.u.constant) = ZEND_ACC_ABSTRACT; }
        |    '{' inner_statement_list '}'    { Z_LVAL($$.u.constant) = 0;    }
    ;
    
    inner_statement_list:
            inner_statement_list  { zend_do_extended_info(TSRMLS_C); } inner_statement { HANDLE_INTERACTIVE(); }
        |    /* empty */
    ;
    
    inner_statement: //具体的函数体  statement
        |    function_declaration_statement
        |    class_declaration_statement
        |    T_HALT_COMPILER '(' ')' ';'   { zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope"); }
    ;
    
    
    //类名::$静态成员变量名字 static_member: class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { $$ = $3; zend_do_fetch_static_member(&$$, &$1 TSRMLS_CC); } ;

      variable_without_objects:
          reference_variable { $$ = $1; }
        | simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); }
      ;

      reference_variable:
          reference_variable '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
        | reference_variable '{' expr '}' { fetch_string_offset(&$$, &$1, &$3 TSRMLS_CC); }
        | compound_variable { zend_do_begin_variable_parse(TSRMLS_C); fetch_simple_variable(&$$, &$1, 1 TSRMLS_CC); }
      ;

     

      compound_variable:
          T_VARIABLE { $$ = $1; }
        | '$' '{' expr '}' { $$ = $3; }
      ;

    
    class_variable_declaration:
            class_variable_declaration ',' T_VARIABLE                    { zend_do_declare_property(&$3, NULL, CG(access_type) TSRMLS_CC); }
        |    class_variable_declaration ',' T_VARIABLE '=' static_scalar    { zend_do_declare_property(&$3, &$5, CG(access_type) TSRMLS_CC); }
        |    T_VARIABLE                        { zend_do_declare_property(&$1, NULL, CG(access_type) TSRMLS_CC); }
        |    T_VARIABLE '=' static_scalar    { zend_do_declare_property(&$1, &$3, CG(access_type) TSRMLS_CC); }
    ;
    
    static_scalar: /* compile-time evaluated scalars */
            common_scalar        { $$ = $1; }
        |    namespace_name         { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); }
        |    T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant);  zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); }
        |    T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); }
        |    '+' static_scalar { ZVAL_LONG(&$1.u.constant, 0); add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
        |    '-' static_scalar { ZVAL_LONG(&$1.u.constant, 0); sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
        |    T_ARRAY '(' static_array_pair_list ')' { $$ = $3; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; }
        |    '[' static_array_pair_list ']' { $$ = $2; Z_TYPE($$.u.constant) = IS_CONSTANT_ARRAY; }
        |    static_class_constant { $$ = $1; }
        |    T_CLASS_C            { $$ = $1; }
    ;
    
    common_scalar:
            T_LNUMBER                     { $$ = $1; }
        |    T_DNUMBER                     { $$ = $1; }
        |    T_CONSTANT_ENCAPSED_STRING    { $$ = $1; }
        |    T_LINE                         { $$ = $1; }
        |    T_FILE                         { $$ = $1; }
        |    T_DIR                       { $$ = $1; }
        |    T_TRAIT_C                    { $$ = $1; }
        |    T_METHOD_C                    { $$ = $1; }
        |    T_FUNC_C                    { $$ = $1; }
        |    T_NS_C                        { $$ = $1; }
        |    T_START_HEREDOC T_ENCAPSED_AND_WHITESPACE T_END_HEREDOC { $$ = $2; CG(heredoc) = Z_STRVAL($1.u.constant); CG(heredoc_len) = Z_STRLEN($1.u.constant); }
        |    T_START_HEREDOC T_END_HEREDOC { ZVAL_EMPTY_STRING(&$$.u.constant); INIT_PZVAL(&$$.u.constant); $$.op_type = IS_CONST; CG(heredoc) = Z_STRVAL($1.u.constant); CG(heredoc_len) = Z_STRLEN($1.u.constant); }
    ;

     

     开始声明类

    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 = 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); 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 {
    //设置opcode opline
    ->opcode = ZEND_DECLARE_CLASS; } LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0); CALCULATE_LITERAL_HASH(opline->op2.constant);
    //先add/update到CG(class_table)中,现在是编译阶段,如果这里不把zend_class_entry存储到CG(class_table)里的话,在执行时,是找不到的zend_class_entry这个的, 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; } }

     

    执行opcode ZEND_DECLARE

    static int ZEND_FASTCALL  ZEND_DECLARE_CLASS_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
    
        SAVE_OPLINE();
        EX_T(opline->result.var).class_entry = do_bind_class(EX(op_array), opline, EG(class_table), 0 TSRMLS_CC);
        CHECK_EXCEPTION();
        ZEND_VM_NEXT_OPCODE();
    }
    
    ZEND_API zend_class_entry *do_bind_class(const zend_op_array* op_array, const zend_op *opline, HashTable *class_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
    {
        zend_class_entry *ce, **pce;
        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;
        }
        if (zend_hash_quick_find(class_table, Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_HASH_P(op1), (void **) &pce)==FAILURE) {
            zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", Z_STRVAL_P(op1));
            return NULL;
        } else {
            ce = *pce;
        }
        ce->refcount++;
        if (zend_hash_quick_add(class_table, Z_STRVAL_P(op2), Z_STRLEN_P(op2)+1, Z_HASH_P(op2), &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
            ce->refcount--;
            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", ce->name);
            }
            return NULL;
        } else {
            if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
                zend_verify_abstract_class(ce TSRMLS_CC);
            }
            return ce;
        }
    }

     

    2.定义变量的编译

    void zend_do_declare_property(const znode *var_name, const znode *value, zend_uint access_type TSRMLS_DC) /* {{{ */
    {
        zval *property;
        zend_property_info *existing_property_info;
        char *comment = NULL;
        int comment_len = 0;
        
       //接口不能包含变量
    if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) { zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables"); }
       //属性不能定义为抽象
    if (access_type & ZEND_ACC_ABSTRACT) { zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract"); }
       //变量前面的修饰符不能为final
    if (access_type & ZEND_ACC_FINAL) { zend_error(E_COMPILE_ERROR, "Cannot declare property %s::$%s final, the final modifier is allowed only for methods and classes", CG(active_class_entry)->name, var_name->u.constant.value.str.val); }   
    //不能多次定义同一变量
    if (zend_hash_find(&CG(active_class_entry)->properties_info, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, (void **) &existing_property_info)==SUCCESS) { zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::$%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val); } ALLOC_ZVAL(property); if (value) { *property = value->u.constant; } else { INIT_PZVAL(property); Z_TYPE_P(property) = IS_NULL; } if (CG(doc_comment)) { comment = CG(doc_comment); comment_len = CG(doc_comment_len); CG(doc_comment) = NULL; CG(doc_comment_len) = 0; } zend_declare_property_ex(CG(active_class_entry), zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + 1, 0 TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC); efree(var_name->u.constant.value.str.val); }

     

     

    ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, const char *doc_comment, int doc_comment_len TSRMLS_DC) /* {{{ */
    {
        zend_property_info property_info, *property_info_ptr;
        const char *interned_name;
        ulong h = zend_get_hash_value(name, name_length+1);
    
        if (!(access_type & ZEND_ACC_PPP_MASK)) {
            access_type |= ZEND_ACC_PUBLIC;
        }
        if (access_type & ZEND_ACC_STATIC) {
            //修饰符为static的,例如 public static $xxx
            if (zend_hash_quick_find(&ce->properties_info, name, name_length + 1, h, (void**)&property_info_ptr) == SUCCESS &&
                (property_info_ptr->flags & ZEND_ACC_STATIC) != 0) {
                property_info.offset = property_info_ptr->offset;
                zval_ptr_dtor(&ce->default_static_members_table[property_info.offset]);
                zend_hash_quick_del(&ce->properties_info, name, name_length + 1, h);
            } else {
                property_info.offset = ce->default_static_members_count++;
                ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval*) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
            }
            ce->default_static_members_table[property_info.offset] = property;
            if (ce->type == ZEND_USER_CLASS) {
                ce->static_members_table = ce->default_static_members_table;
            }
        } else {
            //这里应该是public $xxx这样的变量
            if (zend_hash_quick_find(&ce->properties_info, name, name_length + 1, h, (void**)&property_info_ptr) == SUCCESS &&
                (property_info_ptr->flags & ZEND_ACC_STATIC) == 0) {
                property_info.offset = property_info_ptr->offset;
                zval_ptr_dtor(&ce->default_properties_table[property_info.offset]);
                zend_hash_quick_del(&ce->properties_info, name, name_length + 1, h);
            } else {
                property_info.offset = ce->default_properties_count++;
                ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval*) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
            }
            ce->default_properties_table[property_info.offset] = property;
        }
        if (ce->type & ZEND_INTERNAL_CLASS) {
            switch(Z_TYPE_P(property)) {
                case IS_ARRAY:
                case IS_CONSTANT_ARRAY:
                case IS_OBJECT:
                case IS_RESOURCE:
                    zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
                    break;
                default:
                    break;
            }
        }
        switch (access_type & ZEND_ACC_PPP_MASK) {
            case ZEND_ACC_PRIVATE: {
                    char *priv_name;
                    int priv_name_length;
    
                    zend_mangle_property_name(&priv_name, &priv_name_length, ce->name, ce->name_length, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
                    property_info.name = priv_name;
                    property_info.name_length = priv_name_length;
                }
                break;
            case ZEND_ACC_PROTECTED: {
                    char *prot_name;
                    int prot_name_length;
    
                    zend_mangle_property_name(&prot_name, &prot_name_length, "*", 1, name, name_length, ce->type & ZEND_INTERNAL_CLASS);
                    property_info.name = prot_name;
                    property_info.name_length = prot_name_length;
                }
                break;
            case ZEND_ACC_PUBLIC:
                if (IS_INTERNED(name)) {
                    property_info.name = (char*)name;
                } else {
                    property_info.name = ce->type & ZEND_INTERNAL_CLASS ? zend_strndup(name, name_length) : estrndup(name, name_length);
                }
                property_info.name_length = name_length;
                break;
        }
    
        interned_name = zend_new_interned_string(property_info.name, property_info.name_length+1, 0 TSRMLS_CC);
        if (interned_name != property_info.name) {
            if (ce->type == ZEND_USER_CLASS) {
                efree((char*)property_info.name);
            } else {
                free((char*)property_info.name);
            }
            property_info.name = interned_name;
        }
    
        property_info.flags = access_type; //相应的修饰符
        property_info.h = (access_type & ZEND_ACC_PUBLIC) ? h : zend_get_hash_value(property_info.name, property_info.name_length+1);
    
        property_info.doc_comment = doc_comment;
        property_info.doc_comment_len = doc_comment_len;
    
        property_info.ce = ce; //属于哪个类
    
        zend_hash_quick_update(&ce->properties_info, name, name_length+1, h, &property_info, sizeof(zend_property_info), NULL);
    
        return SUCCESS;
    }

     

    类名::$静态成员名字

    void zend_do_fetch_static_member(znode *result, znode *class_name TSRMLS_DC) /* {{{ */
    {
        znode class_node;
        zend_llist *fetch_list_ptr;
        zend_llist_element *le;
        zend_op *opline_ptr;
        zend_op opline;
    
        if (class_name->op_type == IS_CONST &&
            ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
            zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
            class_node = *class_name;
        } else {
            zend_do_fetch_class(&class_node, class_name TSRMLS_CC);
        }
        zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
        if (result->op_type == IS_CV) {
            init_op(&opline TSRMLS_CC);
    
            opline.opcode = ZEND_FETCH_W;
            opline.result_type = IS_VAR;
            opline.result.var = get_temporary_variable(CG(active_op_array));
            opline.op1_type = IS_CONST;

         //将result的name存储到CG(active_op_array)中的literal数组中,返回key给opline.op1.constant LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)
    ->vars[result->u.op.var].name), CG(active_op_array)->vars[result->u.op.var].name_len, 0);
    CALCULATE_LITERAL_HASH(opline.op1.constant); GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant);
    if (class_node.op_type == IS_CONST) { opline.op2_type = IS_CONST;

    //将class_node里面的zval值 存储在CG(active_op_array)中的literal数组中,返回key给opline.op2.costant opline.op2.constant
    = zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); } else { SET_NODE(opline.op2, &class_node); } GET_NODE(result,opline.result); opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; opline_ptr = &opline; zend_llist_add_element(fetch_list_ptr, &opline); } else { le = fetch_list_ptr->head; opline_ptr = (zend_op *)le->data; if (opline_ptr->opcode != ZEND_FETCH_W && opline_ptr->op1_type == IS_CV) { init_op(&opline TSRMLS_CC); opline.opcode = ZEND_FETCH_W; opline.result_type = IS_VAR; opline.result.var = get_temporary_variable(CG(active_op_array)); opline.op1_type = IS_CONST; LITERAL_STRINGL(opline.op1, estrdup(CG(active_op_array)->vars[opline_ptr->op1.var].name), CG(active_op_array)->vars[opline_ptr->op1.var].name_len, 0); CALCULATE_LITERAL_HASH(opline.op1.constant); GET_POLYMORPHIC_CACHE_SLOT(opline.op1.constant); if (class_node.op_type == IS_CONST) { opline.op2_type = IS_CONST; opline.op2.constant = zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); } else { SET_NODE(opline.op2, &class_node); } opline.extended_value |= ZEND_FETCH_STATIC_MEMBER; COPY_NODE(opline_ptr->op1, opline.result); zend_llist_prepend_element(fetch_list_ptr, &opline); } else { if (opline_ptr->op1_type == IS_CONST) { GET_POLYMORPHIC_CACHE_SLOT(opline_ptr->op1.constant); } if (class_node.op_type == IS_CONST) { opline_ptr->op2_type = IS_CONST; opline_ptr->op2.constant = zend_add_class_name_literal(CG(active_op_array), &class_node.u.constant TSRMLS_CC); } else { SET_NODE(opline_ptr->op2, &class_node); } opline_ptr->extended_value |= ZEND_FETCH_STATIC_MEMBER; } } }

     

     

    static int ZEND_FASTCALL zend_fetch_var_address_helper_SPEC_CONST_CONST(int type, ZEND_OPCODE_HANDLER_ARGS)
    {
        USE_OPLINE
        zend_free_op free_op1;
        zval *varname;
        zval **retval;
        zval tmp_varname;
        HashTable *target_symbol_table;
        ulong hash_value;
    
        SAVE_OPLINE();
        varname = opline->op1.zv;
    
    
    
        if (IS_CONST != IS_UNUSED) {
            zend_class_entry *ce;
    
            if (IS_CONST == IS_CONST) {
                if (CACHED_PTR(opline->op2.literal->cache_slot)) {
                    ce = CACHED_PTR(opline->op2.literal->cache_slot); //从cache中取出类
                } else {
                    ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op2.zv), Z_STRLEN_P(opline->op2.zv), opline->op2.literal + 1, 0 TSRMLS_CC);
                    if (UNEXPECTED(ce == NULL)) {
                        if (IS_CONST != IS_CONST && varname == &tmp_varname) {
                            zval_dtor(&tmp_varname);
                        }
    
                        CHECK_EXCEPTION();
                        ZEND_VM_NEXT_OPCODE();
                    }
                    CACHE_PTR(opline->op2.literal->cache_slot, ce); //将类放入cache中
                }
            } else {
                ce = EX_T(opline->op2.var).class_entry;
            }
            retval = zend_std_get_static_property(ce, Z_STRVAL_P(varname), Z_STRLEN_P(varname), 0, ((IS_CONST == IS_CONST) ? opline->op1.literal : NULL) TSRMLS_CC);
    
        } else {
        //代码省略
    }
    

     #define CACHED_PTR(num)
      EG(active_op_array)->run_time_cache[(num)]

    
    

     #define CACHE_PTR(num, ptr) do {
      EG(active_op_array)->run_time_cache[(num)] = (ptr);
     } while (0)

    
    
    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_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;
        }
    
    
    
    
    
    ZEND_API zval **zend_std_get_static_property(zend_class_entry *ce, const char *property_name, int property_name_len, zend_bool silent, const zend_literal *key TSRMLS_DC) /* {{{ */
    {
        zend_property_info *property_info;
        ulong hash_value;
    
        if (UNEXPECTED(!key) ||
            (property_info = CACHED_POLYMORPHIC_PTR(key->cache_slot, ce)) == NULL) { //如果cache中没有,那么从ce->properties_info中查找
            if (EXPECTED(key != NULL)) {
                hash_value = key->hash_value;
            } else {
                hash_value = zend_hash_func(property_name, property_name_len+1);
            }
    
            if (UNEXPECTED(zend_hash_quick_find(&ce->properties_info, property_name, property_name_len+1, hash_value, (void **) &property_info)==FAILURE)) {
                if (!silent) {
                    zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
                }
                return NULL;
            }
    
    #if DEBUG_OBJECT_HANDLERS
            zend_printf("Access type for %s::%s is %s
    ", ce->name, property_name, zend_visibility_string(property_info->flags));
    #endif
    
            if (UNEXPECTED(!zend_verify_property_access(property_info, ce TSRMLS_CC))) {
                if (!silent) {
                    zend_error_noreturn(E_ERROR, "Cannot access %s property %s::$%s", zend_visibility_string(property_info->flags), ce->name, property_name);
                }
                return NULL;
            }
    
            if (UNEXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0)) {
                if (!silent) {
                    zend_error_noreturn(E_ERROR, "Access to undeclared static property: %s::$%s", ce->name, property_name);
                }
                return NULL;
            }
    
            zend_update_class_constants(ce TSRMLS_CC); //不知道为什么这里update?
    
            if (EXPECTED(key != NULL)) {
                CACHE_POLYMORPHIC_PTR(key->cache_slot, ce, property_info); //放入cache中
            }
        }
    
        return &CE_STATIC_MEMBERS(ce)[property_info->offset];
    }

    //检查成员变量的权限

    static zend_always_inline int zend_verify_property_access(zend_property_info *property_info, zend_class_entry *ce TSRMLS_DC) /* {{{ */
    {
      switch (property_info->flags & ZEND_ACC_PPP_MASK) {
      case ZEND_ACC_PUBLIC:
        return 1;
      case ZEND_ACC_PROTECTED:
        return zend_check_protected(property_info->ce, EG(scope));
      case ZEND_ACC_PRIVATE:
        if ((ce==EG(scope) || property_info->ce == EG(scope)) && EG(scope)) {
          return 1;
        } else {
          return 0;
        }
        break;
      }
      return 0;
    }

     

    #define CACHED_POLYMORPHIC_PTR(num, ce)
      ((EG(active_op_array)->run_time_cache[(num)] == (ce)) ?
      EG(active_op_array)->run_time_cache[(num) + 1] :
      NULL)

    
    

    #define CACHE_POLYMORPHIC_PTR(num, ce, ptr) do {
      EG(active_op_array)->run_time_cache[(num)] = (ce);
      EG(active_op_array)->run_time_cache[(num) + 1] = (ptr);
    } while (0)

     

    define CE_STATIC_MEMBERS(ce) ((ce)->static_members_table)



  • 相关阅读:
    作业
    第一次作业
    临时和永久关闭firewalld与selinux
    联合删除
    使用CascadingDropDown实现级联式下拉框
    使用createElement动态创建HTML对象.
    关于DotNetZip的用法
    网站性能优化:cache-control设置详解
    百度蜘蛛Baiduspider User-Agent字段更新与IP判断
    (转)一个简单,方便的七牛云存储的客户端(收藏)
  • 原文地址:https://www.cnblogs.com/taek/p/4126642.html
Copyright © 2011-2022 走看看