]> granicus.if.org Git - php/commitdiff
- Implement public/protected/private methods.
authorZeev Suraski <zeev@php.net>
Fri, 6 Dec 2002 17:09:44 +0000 (17:09 +0000)
committerZeev Suraski <zeev@php.net>
Fri, 6 Dec 2002 17:09:44 +0000 (17:09 +0000)
- Prevent instantiation of classes with abstract methods.
Based in part on Marcus's patch.

Zend/zend.c
Zend/zend.h
Zend/zend_API.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_globals.h
Zend/zend_hash.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.l

index b60f8033ac72674dbff6734467b1c291bc51c58b..b4b6d0ef06482f75a4a48ad29cc24e73de699032 100644 (file)
@@ -354,6 +354,7 @@ static void register_standard_class(void)
        zend_standard_class_def->handle_property_set = NULL;
        zend_standard_class_def->refcount = 1;
        zend_standard_class_def->constants_updated = 0;
+       zend_standard_class_def->ce_flags = 0;
 
        zend_hash_add(GLOBAL_CLASS_TABLE, "stdclass", sizeof("stdclass"), &zend_standard_class_def, sizeof(zend_class_entry *), NULL);
 }
index bcb93d85da2d03020973370458318669a1b044bb..123a241d5b486e72c8f153373ec432caae0391c4 100644 (file)
@@ -295,6 +295,8 @@ typedef struct _zend_overloaded_element {
 /* A lot of stuff needs shifiting around in order to include zend_compile.h here */
 union _zend_function;
 
+#define ZEND_CE_ABSTRACT ZEND_ACC_ABSTRACT /* same as ZEND_ACC_ABSTRACT */
+
 struct _zend_class_entry {
        char type;
        char *name;
@@ -302,6 +304,7 @@ struct _zend_class_entry {
        struct _zend_class_entry *parent; 
        int refcount;
        zend_bool constants_updated;
+       zend_uint ce_flags;
 
        HashTable function_table;
        HashTable default_properties;
index 47636708868e34c02a162ac85488d12f413c9352..78393d4b7199c4953e49e05be302ae7908013fb8 100644 (file)
@@ -1236,6 +1236,7 @@ ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_c
        class_entry->parent = NULL;
        class_entry->refcount = 1;
        class_entry->constants_updated = 0;
+       class_entry->ce_flags = 0;
        zend_hash_init(&class_entry->default_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
        zend_hash_init(&class_entry->private_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
        zend_hash_init(&class_entry->protected_properties, 0, NULL, ZVAL_PTR_DTOR, 1);
index d50c424f338041b6225a9b02098d681faaa74202..071502ddacbcd2d27d5b622a580034e52fcc76ba 100644 (file)
@@ -909,6 +909,16 @@ void zend_do_free(znode *op1 TSRMLS_DC)
        }               
 }
 
+
+int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier)
+{
+       if (current_access_type->u.constant.value.lval & ZEND_FN_PPP_MASK) {
+               zend_error(E_COMPILE_ERROR, "Multiple access type modifiers are not allowed");
+       }
+       return (current_access_type->u.constant.value.lval | new_modifier->u.constant.value.lval);
+}
+
+
 void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags  TSRMLS_DC)
 {
        zend_op_array op_array;
@@ -950,6 +960,9 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
                                zend_error(E_COMPILE_ERROR, "Cannot redeclare %s()", name);
                        }
                }
+               if (fn_flags & ZEND_ACC_ABSTRACT) {
+                       CG(active_class_entry)->ce_flags |= ZEND_ACC_ABSTRACT;
+               }
 
                if ((short_class_name_length == name_len) && (!memcmp(short_class_name, name, name_len))) {
                        CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
@@ -1502,7 +1515,6 @@ ZEND_API void function_add_ref(zend_function *function)
        }
 }
 
-
 static void do_inherit_parent_constructor(zend_class_entry *ce)
 {
        zend_function *function;
@@ -1529,27 +1541,75 @@ static void do_inherit_parent_constructor(zend_class_entry *ce)
        ce->__call = ce->parent->__call;
 }
 
-static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent) {
+
+char *zend_visibility_string(zend_uint fn_flags)
+{
+       if (fn_flags & ZEND_ACC_PRIVATE) {
+               return "private";
+       }
+       if (fn_flags & ZEND_ACC_PROTECTED) {
+               return "protected";
+       }
+       if (fn_flags & ZEND_ACC_PUBLIC) {
+               return "public";
+       }
+       return "";
+}
+
+
+static void do_inherit_method(zend_function *function)
+{
+       /* The class entry of the derived function intentionally remains the same
+        * as that of the parent class.  That allows us to know in which context
+        * we're running, and handle private method calls properly.
+        */
+       if (function->common.fn_flags & ZEND_ACC_ABSTRACT) {
+               function->op_array.scope->ce_flags |= ZEND_ACC_ABSTRACT;
+       }
+       function_add_ref(function);
+}
+
+
+static zend_bool do_inherit_method_check(zend_function *child, zend_function *parent)
+{
        zend_uint child_flags  = child->common.fn_flags;
        zend_uint parent_flags = parent->common.fn_flags;
 
+       /* we do not inherit private methods */
+/*     assert(!(parent_flags & ZEND_ACC_PRIVATE));     */
+
        /* You cannot change from static to non static and vice versa.
         */
-       if ((child_flags & FN_STATIC) != (parent_flags & FN_STATIC)) {
-               if (child->common.fn_flags & FN_STATIC) {
-                       zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+       if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
+               if (child->common.fn_flags & ZEND_ACC_STATIC) {
+                       zend_error(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
                } else {
-                       zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+                       zend_error(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
                }
        }
-       /* Disallow makeing an inherited method abstract.
+       /* Disallow making an inherited method abstract.
+        * Also check the visibility and copy it if needed. This must be done last
+        * since we may change the child flags here.
+        * Again first detect more than one error to make normal operation faster.
         */
-       if (child_flags & FN_ABSTRACT) {
-               zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", FN_SCOPE_NAME(parent), child->common.function_name, FN_SCOPE_NAME(child));
+       if ((child_flags & (ZEND_FN_PPP_MASK|ZEND_ACC_ABSTRACT)) != (parent_flags & ZEND_FN_PPP_MASK)) {
+               if (child_flags & ZEND_ACC_ABSTRACT) {
+                       zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name, ZEND_FN_SCOPE_NAME(child));
+               }
+               if (!(child_flags & ZEND_FN_PPP_MASK) || (((child_flags|parent_flags) & ZEND_FN_PPP_MASK) == ZEND_ACC_PUBLIC)) {
+                       /* this is no error since we copy visibility here */
+                       /* child->common.fn_flags &= ~ZEND_FN_PPP_MASK; do not clear added public */
+                       child->common.fn_flags |= parent_flags & ZEND_FN_PPP_MASK;
+               } else {
+                       zend_error(E_COMPILE_ERROR, "Cannot redeclare %s %s::%s() as %s %s::%s()", 
+                               zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), parent->common.function_name, 
+                               zend_visibility_string(child_flags),  ZEND_FN_SCOPE_NAME(child),  child->common.function_name);
+               }
        }
        return SUCCESS;
 }
 
+
 void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
 {
        zval *tmp;
@@ -1560,14 +1620,17 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
        /* STATIC_MEMBERS_FIXME */
 /*     zend_hash_merge(ce->static_members, parent_ce->static_members, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); */
        zend_hash_merge(&ce->constants_table, &parent_ce->constants_table, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0);
-       zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, sizeof(zend_function), (zend_bool (*)(void *, void *))do_inherit_method_check);
+       zend_hash_merge_ex(&ce->function_table, &parent_ce->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (zend_bool (*)(void *, void *)) do_inherit_method_check);
        ce->parent = parent_ce;
-       if (!ce->handle_property_get)
-          ce->handle_property_get      = parent_ce->handle_property_get;
-       if (!ce->handle_property_set)
+       if (!ce->handle_property_get) {
+               ce->handle_property_get = parent_ce->handle_property_get;
+       }
+       if (!ce->handle_property_set) {
                ce->handle_property_set = parent_ce->handle_property_set;
-       if (!ce->handle_function_call)
+       }
+       if (!ce->handle_function_call) {
                ce->handle_function_call = parent_ce->handle_function_call;
+       }
        do_inherit_parent_constructor(ce);
 }
 
@@ -1582,6 +1645,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
        new_class_entry->name_length = name_length;
        new_class_entry->refcount = 1;
        new_class_entry->constants_updated = 0;
+       new_class_entry->ce_flags = 0;
 
        zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
 
@@ -2055,6 +2119,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
        }
        new_class_entry->refcount = 1;
        new_class_entry->constants_updated = 0;
+       new_class_entry->ce_flags = 0;
        
        zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
 
@@ -2134,7 +2199,8 @@ void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_le
        *dest_length = prop_name_length;
 }
 
-void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC)
+
+void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC)
 {
        zval *property;
 
@@ -2147,8 +2213,8 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
                property->type = IS_NULL;
        }
 
-       switch (declaration_type) {
-               case T_PRIVATE:
+       switch (CG(access_type)) {
+               case ZEND_ACC_PRIVATE:
                        {
                                char *priv_name;
                                int priv_name_length;
@@ -2162,7 +2228,7 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
                                zend_hash_update(&CG(active_class_entry)->private_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
                                break;
                        }
-               case T_PROTECTED:
+               case ZEND_ACC_PROTECTED:
                        {
                                char *prot_name;
                                int prot_name_length;
@@ -2188,19 +2254,37 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ
                                efree(prot_name);
                                break;
                        }
-               case T_VAR:
+               case ZEND_ACC_PUBLIC:
                        zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
                        break;
-               case T_STATIC:
+               case ZEND_ACC_STATIC:
                        zend_hash_update(CG(active_class_entry)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
                        break;
-               case T_CONST:
-                       zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
-                       break;
        }
        FREE_PNODE(var_name);
 }
 
+
+void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC)
+{
+       zval *property;
+
+       ALLOC_ZVAL(property);
+
+       if (value) {
+               *property = value->u.constant;
+       } else {
+               INIT_PZVAL(property);
+               property->type = IS_NULL;
+       }
+
+       zend_hash_update(&CG(active_class_entry)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL);
+
+       FREE_PNODE(var_name);
+}
+
+
+
 void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC)
 {
        zend_op opline;
index d712f5f965705f0ebd90302cc6dce00d7753fe4c..7291a3a9b5e01276cd201c376003a08374c1bc70 100644 (file)
@@ -88,9 +88,21 @@ typedef struct _zend_brk_cont_element {
 } zend_brk_cont_element;
 
 
-#define FN_STATIC 0x01
+#define ZEND_ACC_STATIC                0x01
+#define ZEND_ACC_ABSTRACT      0x02
 
-#define FN_ABSTRACT  0x02
+/* No visibility is the same as public visibility.
+ * For inheritance no visibility means inheriting the visibility.
+ */
+#define ZEND_ACC_PUBLIC    0x10
+#define ZEND_ACC_PROTECTED 0x20
+#define ZEND_ACC_PRIVATE   0x40
+
+/* AND mask for accessing only public/protected/private of fn_flags
+ */
+#define ZEND_FN_PPP_MASK  0xF0
+
+char *zend_visibility_string(zend_uint fn_flags);
 
 struct _zend_op_array {
        zend_uchar type;                        /* MUST be the first element of this struct! */
@@ -138,7 +150,7 @@ typedef struct _zend_internal_function {
        void (*handler)(INTERNAL_FUNCTION_PARAMETERS);
 } zend_internal_function;
 
-#define FN_SCOPE_NAME(function)  ((function) && (function)->common.scope ? (function)->common.scope->name : "")
+#define ZEND_FN_SCOPE_NAME(function)  ((function) && (function)->common.scope ? (function)->common.scope->name : "")
 
 typedef union _zend_function {
        zend_uchar type;        /* MUST be the first element of this struct! */
@@ -295,6 +307,7 @@ void zend_do_add_char(znode *result, znode *op1, znode *op2 TSRMLS_DC);
 void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC);
 void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);
 
+int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
 void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC);
 void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
 void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC);
@@ -337,7 +350,8 @@ void zend_do_default_before_statement(znode *case_list, znode *default_token TSR
 
 void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znode *parent_class_name TSRMLS_DC);
 void zend_do_end_class_declaration(znode *class_token TSRMLS_DC);
-void zend_do_declare_property(znode *var_name, znode *value, int declaration_type TSRMLS_DC);
+void zend_do_declare_property(znode *var_name, znode *value TSRMLS_DC);
+void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC);
 
 void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS_DC);
 
index 97cdcb05feeecb35a7c4f05b65a9f08f9af1b0d4..62594775017c6ebc0587c644fbc02388ff682590 100644 (file)
@@ -2251,6 +2251,55 @@ int zend_init_ctor_call_handler(ZEND_OPCODE_HANDLER_ARGS)
        NEXT_OPCODE();
 }
 
+
+/* Ensures that we're allowed to call a private method.
+ * Will update EX(fbc) with the correct handler as necessary.
+ */
+inline int zend_check_private(zend_execute_data *execute_data, zend_class_entry *ce, int fn_flags, char *function_name_strval, int function_name_strlen TSRMLS_DC)
+{
+       if (!ce) {
+               return 0;
+       }
+
+       /* We may call a private function in one of two cases:
+        * 1.  The scope of the function is the same as the class entry of our object
+        * 2.  The class of our object is different, but a private function exists
+        *     in one of the ancestor that corresponds to our object's ce.
+        */
+       if (EX(fbc)->common.scope == ce) {
+               /* rule #1 checks out ok, allow the function call */
+               return 1;
+       }
+
+       /* Check rule #2 */
+       while (ce) {
+               if (ce == EG(scope)) {
+                       if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==SUCCESS
+                               && EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE
+                               && EX(fbc)->common.scope == EG(scope)) {
+                               return 1;
+                       }
+                       break;
+               }
+               ce = ce->parent;
+       }
+       return 0;
+}
+
+/* Ensures that we're allowed to call a protected method.
+ */
+inline int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope, int fn_flags)
+{
+       while (ce) {
+               if (ce==scope) {
+                       return 1;
+               }
+               ce = ce->parent;
+       }
+       return 0;
+}
+
+
 int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
        zval *function_name;
@@ -2268,15 +2317,33 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
        EX(object) = get_obj_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R TSRMLS_CC);
                        
        if (EX(object) && EX(object)->type == IS_OBJECT) {
+
+               /* First, locate the function. */
                EX(fbc) = Z_OBJ_HT_P(EX(object))->get_method(EX(object), function_name_strval, function_name_strlen TSRMLS_CC);
                if (!EX(fbc)) {
-                       zend_error(E_ERROR, "Call to undefined function: %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
+                       zend_error(E_ERROR, "Call to undefined method %s::%s()", Z_OBJ_CLASS_NAME_P(EX(object)), function_name_strval);
+               }
+
+               if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
+                       /* No further checks necessary, most common case */
+               } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+                       /* Ensure that if we're calling a private function, we're allowed to do so.
+                        */
+                       if (!zend_check_private(execute_data, EX(object)->value.obj.handlers->get_class_entry(EX(object) TSRMLS_CC), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
+                               zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+                       }
+               } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
+                       /* Ensure that if we're calling a protected function, we're allowed to do so.
+                        */
+                       if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
+                               zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+                       }
                }
        } else {
                zend_error(E_ERROR, "Call to a member function %s() on a non-object", function_name_strval);
        }
 
-       if (EX(fbc)->common.fn_flags & FN_STATIC) {
+       if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
                if (!PZVAL_IS_REF(EX(object))) {
@@ -2305,7 +2372,6 @@ int zend_init_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
 int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
        zval *function_name;
-       zend_function *function;
        zval tmp;
        zend_class_entry *ce;
        zend_bool is_const;
@@ -2335,8 +2401,25 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
 
        EX(calling_scope) = ce;
 
-       if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) {
-               zend_error(E_ERROR, "Call to undefined function: %s::%s()", ce->name, function_name_strval);
+       if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &EX(fbc))==FAILURE) {
+               zend_error(E_ERROR, "Call to undefined method %s::%s()", ce->name, function_name_strval);
+       }
+       EX(calling_scope) = EX(fbc)->common.scope;
+
+       if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PUBLIC) {
+               /* No further checks necessary, most common case */
+       } else if (EX(fbc)->op_array.fn_flags & ZEND_ACC_PRIVATE) {
+               /* Ensure that if we're calling a private function, we're allowed to do so.
+                */
+               if (!zend_check_private(execute_data, EG(scope), EX(fbc)->common.fn_flags, function_name_strval, function_name_strlen TSRMLS_CC)) {
+                       zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+               }
+       } else if ((EX(fbc)->common.fn_flags & ZEND_ACC_PROTECTED)) {
+               /* Ensure that if we're calling a protected function, we're allowed to do so.
+                */
+               if (!zend_check_protected(EG(scope), EX(fbc)->common.scope, EX(fbc)->common.fn_flags)) {
+                       zend_error(E_ERROR, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(EX(fbc)->common.fn_flags), ZEND_FN_SCOPE_NAME(EX(fbc)), function_name_strval, EG(scope) ? EG(scope)->name : "");
+               }
        }
 
        if (!is_const) {
@@ -2344,9 +2427,7 @@ int zend_init_static_method_call_handler(ZEND_OPCODE_HANDLER_ARGS)
                FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
        }
 
-       EX(fbc) = function;
-
-       if (function->common.fn_flags & FN_STATIC) {
+       if (EX(fbc)->common.fn_flags & ZEND_ACC_STATIC) {
                EX(object) = NULL;
        } else {
                if ((EX(object) = EG(This))) {
@@ -2916,6 +2997,9 @@ int zend_switch_free_handler(ZEND_OPCODE_HANDLER_ARGS)
 
 int zend_new_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
+       if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_ABSTRACT) {
+               zend_error(E_ERROR, "Cannot instanciate abstract class %s", EX_T(EX(opline)->op1.u.var).EA.class_entry->name);
+       }
        EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
        ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr);
        object_init_ex(EX_T(EX(opline)->result.u.var).var.ptr, EX_T(EX(opline)->op1.u.var).EA.class_entry);
index 8e1fc29a3a410102932cf9528c4001f49d7c65a2..aec96b7b300db70e712f2e2196df6e58909713bd 100644 (file)
@@ -123,6 +123,8 @@ struct _zend_compiler_globals {
        zend_bool increment_lineno;
 
        zend_llist import_commands;
+
+       int access_type;
 };
 
 
index 6962d066290bb282e1944bd3cd8447ca2bbcafff..2451d4ae50fa86d9208cebd396f07b8ad146ddb2 100644 (file)
@@ -39,6 +39,7 @@ typedef int  (*compare_func_t)(const void *, const void * TSRMLS_DC);
 typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC);
 typedef void (*dtor_func_t)(void *pDest);
 typedef void (*copy_ctor_func_t)(void *pElement);
+typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam);
 
 struct _hashtable;
 
index 45b2b78bc065205e0678120a5e0e1f0153d22906..926c2190bf15f736a024c141b523a7d0e329b818 100644 (file)
 %token T_THROW
 %token T_USE
 %token T_GLOBAL
-%token T_STATIC
-%token T_ABSTRACT
-%token T_PRIVATE
-%token T_PROTECTED
+%right T_STATIC T_ABSTRACT T_FINAL T_PRIVATE T_PROTECTED T_PUBLIC
 %token T_VAR
 %token T_UNSET
 %token T_ISSET
@@ -273,6 +270,12 @@ class_declaration_statement:
 ;
 
 
+is_reference:
+               /* empty */     { $$.op_type = ZEND_RETURN_VAL; }
+       |       '&'                     { $$.op_type = ZEND_RETURN_REF; }
+;
+
+
 unticked_function_declaration_statement:
                T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, 0 TSRMLS_CC); }
                        '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
@@ -437,46 +440,53 @@ class_statement_list:
 
 
 class_statement:
-               class_variable_declaration ';'
+               variable_modifier { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
        |       class_constant_declaration ';'
-       |       is_static T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '(' 
+       |       method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '(' 
                        parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); }
+       |       T_ABSTRACT method_modifiers T_FUNCTION { $3.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$6, 1, $5.op_type, $2.u.constant.value.lval | ZEND_ACC_ABSTRACT TSRMLS_CC); } '(' 
+                       parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$3 TSRMLS_CC); } ';'
        |       T_CLASS T_STRING extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
-       |       T_ABSTRACT T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, FN_ABSTRACT TSRMLS_CC); } '(' 
-                       parameter_list ')' { zend_do_abstract_method(TSRMLS_C); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
 ;
 
-is_static:
-               T_STATIC        { $$.u.constant.value.lval = FN_STATIC; }
-       |       /* empty */ { $$.u.constant.value.lval = 0; }
+variable_modifier:
+               access_modifier         { $$ = $1; }
+       |       T_VAR                           { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
+       |       T_STATIC                        { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
 ;
-       
-is_reference:
-               /* empty */     { $$.op_type = ZEND_RETURN_VAL; }
-       |       '&'                     { $$.op_type = ZEND_RETURN_REF; }
+
+method_modifiers:
+               /* empty */                                                     { $$.u.constant.value.lval = 0; }
+       |       non_empty_method_modifiers                      { $$ = $1; }
 ;
 
-class_variable_declaration:
-               class_variable_declaration ',' T_VARIABLE                                       { zend_do_declare_property(&$3, NULL, $1.op_type TSRMLS_CC); }
-       |       class_variable_declaration ',' T_VARIABLE '=' static_scalar     { zend_do_declare_property(&$3, &$5, $1.op_type TSRMLS_CC); }
-       |       class_declaration_type T_VARIABLE                                               { $$ = $1; zend_do_declare_property(&$2, NULL, $1.op_type TSRMLS_CC); }
-       |       class_declaration_type T_VARIABLE '=' static_scalar     { $$ = $1; zend_do_declare_property(&$2, &$4, $1.op_type TSRMLS_CC); }
+non_empty_method_modifiers:
+               T_STATIC                                                        { $$.u.constant.value.lval = ZEND_ACC_STATIC; }
+       |       access_modifier                                         { $$ = $1; }
+       |       non_empty_method_modifiers T_STATIC                     { $$.u.constant.value.lval = $1.u.constant.value.lval | ZEND_ACC_STATIC; }
+       |       non_empty_method_modifiers access_modifier      { $$.u.constant.value.lval = zend_do_verify_access_types(&$1, &$2); }
 ;
 
-class_declaration_type:
-               T_VAR           { $$.op_type = T_VAR; }
-       |       T_STATIC        { $$.op_type = T_STATIC; }
-       |       T_PRIVATE       { $$.op_type = T_PRIVATE; }
-       |       T_PROTECTED     { $$.op_type = T_PROTECTED; }
+access_modifier:
+               T_PUBLIC                                { $$.u.constant.value.lval = ZEND_ACC_PUBLIC; }
+       |       T_PROTECTED                             { $$.u.constant.value.lval = ZEND_ACC_PROTECTED; }
+       |       T_PRIVATE                               { $$.u.constant.value.lval = ZEND_ACC_PRIVATE; }
+;
+
+class_variable_declaration:
+               class_variable_declaration ',' T_VARIABLE                                       { zend_do_declare_property(&$3, NULL TSRMLS_CC); }
+       |       class_variable_declaration ',' T_VARIABLE '=' static_scalar     { zend_do_declare_property(&$3, &$5 TSRMLS_CC); }
+       |       T_VARIABLE                                              { zend_do_declare_property(&$1, NULL TSRMLS_CC); }
+       |       T_VARIABLE '=' static_scalar    { zend_do_declare_property(&$1, &$3 TSRMLS_CC); }
 ;
 
 class_constant_declaration:
-       |       T_CONST ',' T_STRING '=' static_scalar  { zend_do_declare_property(&$3, &$5, T_CONST TSRMLS_CC); }
-       |       T_CONST T_STRING '=' static_scalar      { zend_do_declare_property(&$2, &$4, T_CONST TSRMLS_CC); }
+               class_constant_declaration ',' T_STRING '=' static_scalar       { zend_do_declare_class_constant(&$3, &$5 TSRMLS_CC); }
+       |       T_CONST T_STRING '=' static_scalar      { zend_do_declare_class_constant(&$2, &$4 TSRMLS_CC); }
 ;
 
 echo_expr_list:        
-       |       echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
+               echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); }
        |       expr                                    { zend_do_echo(&$1 TSRMLS_CC); }
 ;
 
index 57fe3fc8bf35bbf0b42d3c671a59adb7796ecd35..f26d032389bf96d57e0c9fdfdde302316c4ab5d3 100644 (file)
@@ -730,6 +730,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
        return T_ABSTRACT;
 }
 
+<ST_IN_SCRIPTING>"final" {
+       return T_FINAL;
+}
+
 <ST_IN_SCRIPTING>"private" {
        return T_PRIVATE;
 }
@@ -739,7 +743,7 @@ NEWLINE ("\r"|"\n"|"\r\n")
 }
 
 <ST_IN_SCRIPTING>"public" {
-       return T_VAR;
+       return T_PUBLIC;
 }
 
 <ST_IN_SCRIPTING>"unset" {