php类的实现

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

statement:
        unticked_statement { DO_TICKS(); }
    |    T_STRING ‘:‘ { zend_do_label(&$1 TSRMLS_CC); }
;

unticked_statement:
    |    T_STATIC static_var_list ‘;‘
        |    expr ‘;‘                { zend_do_free(&$1 TSRMLS_CC); }
;

expr:
        r_variable                    { $$ = $1; }
;

r_variable:
    variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; }
;

variable:
        base_variable_with_function_calls T_OBJECT_OPERATOR { zend_do_push_object(&$1 TSRMLS_CC); }
            object_property { zend_do_push_object(&$4 TSRMLS_CC); } method_or_not variable_properties
            { zend_do_pop_object(&$$ TSRMLS_CC); $$.EA = $1.EA | ($7.EA ? $7.EA : $6.EA); }
    |    base_variable_with_function_calls { $$ = $1; }
;

base_variable_with_function_calls:
        base_variable                { $$ = $1; }
    |    array_function_dereference    { $$ = $1; }
    |    function_call { zend_do_begin_variable_parse(TSRMLS_C); $$ = $1; $$.EA = ZEND_PARSED_FUNCTION_CALL; }
;

base_variable:
        reference_variable { $$ = $1; $$.EA = ZEND_PARSED_VARIABLE; }
    |    simple_indirect_reference reference_variable { zend_do_indirect_references(&$$, &$1, &$2 TSRMLS_CC); $$.EA = ZEND_PARSED_VARIABLE; }
    |    static_member { $$ = $1; $$.EA = ZEND_PARSED_STATIC_MEMBER; }
;
//类名::$静态成员变量名字
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); }

;

static_var_list:
        static_var_list ‘,‘ T_VARIABLE { zend_do_fetch_static_variable(&$3, NULL, ZEND_FETCH_STATIC TSRMLS_CC); }
    |    static_var_list ‘,‘ T_VARIABLE ‘=‘ static_scalar { zend_do_fetch_static_variable(&$3, &$5, ZEND_FETCH_STATIC TSRMLS_CC); }
    |    T_VARIABLE  { zend_do_fetch_static_variable(&$1, NULL, ZEND_FETCH_STATIC TSRMLS_CC); }
    |    T_VARIABLE ‘=‘ static_scalar { zend_do_fetch_static_variable(&$1, &$3, ZEND_FETCH_STATIC TSRMLS_CC); }

;

function_declaration_statement:
        unticked_function_declaration_statement    { DO_TICKS(); }
;

class_declaration_statement:
        unticked_class_declaration_statement    { DO_TICKS(); }
;

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

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

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

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

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;
        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;
            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);
            } 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);
            }
        } 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 {
    //代码省略
}

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 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) {
        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\n", 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);
        }
    }

    return &CE_STATIC_MEMBERS(ce)[property_info->offset];
}
时间: 2024-10-11 21:40:01

php类的实现的相关文章

jvm系列(一):java类的加载机制

java类的加载机制 原文:http://www.cnblogs.com/ityouknow/p/5603287.html 1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构.类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口. 类加载器并不需要等到某个

iOS -- SKSpriteNode类

SKSpriteNode类 继承自 SKNode:UIResponder:NSObject 符合 NSCoding(SKNode)NSCopying(SKNode)NSObject(NSObject) 框架  /System/Library/Frameworks/SpriteKit.framework 可用性 可用于iOS 7.0或者更晚的版本 声明于 SKSpriteNode.h 参考指南 Sprite Kit Progamming Guide 概览 重要提示:这是一个初步的API或者开发技术

iOS -- SKScene类

SKScene类 继承自 SKEffectNode:SKNode:UIResponder:NSObject 符合 NSCoding(SKNode)NSCopying(SKNode)NSObject(NSObject) 框架  /System/Library/Frameworks/SpriteKit.framework 可用性 可用于iOS 7.0或者更晚的版本 声明于 SKScene.h 参考指南 Sprite Kit Progamming Guide 概览 重要提示:这是一个初步的API或者开

iOS -- SKPhysicsWorld类

SKPhysicsWorld类 继承自 NSObject 符合 NSCodingNSObject(NSObject) 框架  /System/Library/Frameworks/SpriteKit.framework 可用性 可用于iOS 7.0或者更晚的版本 声明于 SKPhysicsWorld.h 参考指南 Sprite Kit Progamming Guide 概览 重要提示:这是一个初步的API或者开发技术文档.虽然已经审阅了本文档的技术准确性,但是它不是最终的版本.本机密信息仅适用于

C#嵌套类

嵌套类顾名思义就是类或者结构中定义的类 class Container { class Nested { Nested() { } } } <1>嵌套类的默认访问权限是private ,可以指定为public,protected,private,internal,protected internal.<2>嵌套类型可以访问外部类(包裹嵌套类的类),如果要访问外部类型,要把外部类通过构造函数传进一个实例<3>嵌套类中只能访问外部类中的静态成员,不能直接访问外部类的非静态成

一个实用的C#网页抓取类代码分享

一个实用的C# 网页抓取类 模拟蜘蛛,类中定义了超多的C#采集文章.网页抓取文章的基础技巧,下面分享代码: using System; using System.Data; using System.Configuration; using System.Net; using System.IO; using System.Text; using System.Collections.Generic; using System.Text.RegularExpressions; using Sys

类图(Rose) - Windows XP经典软件系列

最近开始了自己高级数据结构之旅,在这次旅行中,我将持续把一些高级的数据结构从理论到编码都过一遍,同时通过博客形式分享出来,希望大家指出不足之处! 二叉排序树是一种动态排序的数据结构,支持插入.删除.查找等操作,且平均时间复杂度为O(log(N)),但是普通二叉排序树不能保证树退化为一颗分支的情况,此时最坏情况下的时间复杂度为O(N).此时,平衡二叉树的产生了.平衡二叉树是一种动态调整平衡的数据结构,但理想的平衡二叉树很难,于是人们使用AVL.红黑树.Treap.伸展树等来替代平衡二叉树,这些数据

java 类对象使用

在学习反射机制时,总结一下获得类对象方式: 第一种方式:通过类本身来获得对象 Class<?> classname = this.getClass(); 或者this.class 第二种方式:通过子类的实例获取父类对象 ClassName cn = new ClassName(); UserClass = cn.getClass(); Class<?> SubUserClass = UserClass.getSuperclass(); 第三种方式:通过类名加.class获取对象 C

Python-class类的相关总结

在Python中,所有的数据类型都可以视为对象,自定义的对象数据类型就是面向对象中的类(class)的概念. 面向对象编程:object oriented programming简称OOP. 1 ###简单举例,以登记学生的姓名和成绩举例 2 #!/usr/bin/python 3 #-*- coding:utf-8 -*- 4 class Student(object): ##定义student类 5 def __init__(self, name, score): ##__init__可以绑

java String 类 基础笔记

字符串是一个特殊的对象. 字符串一旦初始化就不可以被改变. String s = "abc";//存放于字符串常量池,产生1个对象 String s1=new String("abc");//堆内存中new创建了一个String对象,产生2个对象 String类中的equals比较字符串中的内容. 常用方法: 一:获取 1.获取字符串中字符的个数(长度):length();方法. 2.根据位置获取字符:charAt(int index); 3.根据字符获取在字符串中