]> granicus.if.org Git - php/commitdiff
Require abstract classes to be explicitly declared 'abstract', in order to
authorZeev Suraski <zeev@php.net>
Thu, 6 Mar 2003 22:53:23 +0000 (22:53 +0000)
committerZeev Suraski <zeev@php.net>
Thu, 6 Mar 2003 22:53:23 +0000 (22:53 +0000)
avoid making developers traverse the entire class/interface hierarchy
before they can figure out whether a class is instantiable
(ok, so it makes sense :)

Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_language_parser.y

index c609fa28a10ecc5feefc22c64321747b2de2ba0b..1f89b7e0afccfb95b1a4f77dc441c0a91f97e251 100644 (file)
@@ -2214,9 +2214,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
        new_class_entry->num_interfaces = 0;
 
        zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC);
-       if (class_token->u.constant.value.lval == T_INTERFACE) {
-               new_class_entry->ce_flags |= ZEND_ACC_INTERFACE;
-       }
+       new_class_entry->ce_flags |= class_token->u.constant.value.lval;
 
        if (parent_class_name->op_type != IS_UNUSED) {
                doing_inheritance = 1;
@@ -2250,12 +2248,27 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
 }
 
 
-void zend_do_end_class_declaration(znode *class_token TSRMLS_DC)
+static do_verify_abstract_class(TSRMLS_D)
+{
+       zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+
+       opline->opcode = ZEND_VERIFY_ABSTRACT_CLASS;
+       opline->op1 = CG(implementing_class);
+}
+
+
+void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRMLS_DC)
 {
        do_inherit_parent_constructor(CG(active_class_entry));
+
        if (CG(active_class_entry)->num_interfaces > 0) {
                CG(active_class_entry)->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*CG(active_class_entry)->num_interfaces);
        }
+       if (!(CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE)
+               && !(CG(active_class_entry)->ce_flags & ZEND_ACC_ABSTRACT_CLASS)
+               && ((parent_token->op_type != IS_UNUSED) || (CG(active_class_entry)->num_interfaces > 0))) {
+               do_verify_abstract_class(TSRMLS_C);
+       }
        CG(active_class_entry) = NULL;
 }
 
index 112e0ebb9e84540f702d0db55317582c21a78228..b4d49b2920b99af58aa676cfd70204729c62248a 100644 (file)
@@ -89,19 +89,20 @@ typedef struct _zend_brk_cont_element {
 } zend_brk_cont_element;
 
 
-#define ZEND_ACC_STATIC                0x01
-#define ZEND_ACC_ABSTRACT      0x02
-#define ZEND_ACC_FINAL         0x04
-#define ZEND_ACC_INTERFACE     0x08
+#define ZEND_ACC_STATIC                        0x01
+#define ZEND_ACC_ABSTRACT              0x02
+#define ZEND_ACC_FINAL                 0x04
+#define ZEND_ACC_INTERFACE             0x08
+#define ZEND_ACC_ABSTRACT_CLASS        0x10
 
 /* The order of those must be kept - public < protected < private */
-#define ZEND_ACC_PUBLIC                0x10
-#define ZEND_ACC_PROTECTED     0x20
-#define ZEND_ACC_PRIVATE       0x40
+#define ZEND_ACC_PUBLIC                0x100
+#define ZEND_ACC_PROTECTED     0x200
+#define ZEND_ACC_PRIVATE       0x400
 #define ZEND_ACC_PPP_MASK  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE)
 
-#define ZEND_ACC_CHANGED       0x80
-#define ZEND_ACC_IMPLICIT_PUBLIC       0x100
+#define ZEND_ACC_CHANGED       0x800
+#define ZEND_ACC_IMPLICIT_PUBLIC       0x1000
 
 char *zend_visibility_string(zend_uint fn_flags);
 
@@ -352,7 +353,7 @@ void zend_do_case_after_statement(znode *result, znode *case_token TSRMLS_DC);
 void zend_do_default_before_statement(znode *case_list, znode *default_token TSRMLS_DC);
 
 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_end_class_declaration(znode *class_token, znode *parent_token TSRMLS_DC);
 void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_type TSRMLS_DC);
 void zend_do_declare_class_constant(znode *var_name, znode *value TSRMLS_DC);
 
@@ -663,6 +664,7 @@ int zendlex(znode *zendlval TSRMLS_DC);
 
 #define ZEND_ADD_INTERFACE                     144
 #define ZEND_VERIFY_INSTANCEOF         145
+#define ZEND_VERIFY_ABSTRACT_CLASS     146
 
 /* end of block */
 
index 46897d0967b219d6ed06a520388ba00792bd15db..f0a015293b61c687f292442ef53e2d334c59ef1f 100644 (file)
@@ -3125,7 +3125,7 @@ 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) {
+       if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_ABSTRACT_CLASS)) {
                char *class_type;
 
                if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_INTERFACE) {
@@ -4016,6 +4016,21 @@ int zend_verify_instanceof_handler(ZEND_OPCODE_HANDLER_ARGS)
 }
 
 
+int zend_verify_abstract_class(ZEND_OPCODE_HANDLER_ARGS)
+{
+       zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry;
+       zend_bool declared_abstract = ce->ce_flags & ZEND_ACC_ABSTRACT_CLASS;
+       zend_bool detected_abstract = ce->ce_flags & ZEND_ACC_ABSTRACT;
+
+       if ((ce->ce_flags & ZEND_ACC_ABSTRACT)
+               && !(ce->ce_flags & ZEND_ACC_ABSTRACT_CLASS)) {
+               zend_error(E_ERROR, "Class %s contains abstract methods and must be declared abstract", ce->name);
+       }
+
+       NEXT_OPCODE();
+}
+
+
 void zend_init_opcodes_handlers()
 {
        zend_opcode_handlers[ZEND_NOP] = zend_nop_handler;
@@ -4194,6 +4209,7 @@ void zend_init_opcodes_handlers()
 
        zend_opcode_handlers[ZEND_ADD_INTERFACE] = zend_add_interface_handler;
        zend_opcode_handlers[ZEND_VERIFY_INSTANCEOF] = zend_verify_instanceof_handler;
+       zend_opcode_handlers[ZEND_VERIFY_ABSTRACT_CLASS] = zend_verify_abstract_class;
 }
 
 /*
index c25ce39f08b2262fbddb1c5f44d4cc2eb3868515..d81f62e9081177ce82b998cb494fdf87e53b2995 100644 (file)
@@ -294,13 +294,14 @@ unticked_class_declaration_statement:
                        implements_list
                        '{'
                                class_statement_list
-                       '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
+                       '}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
 ;
 
 
 class_entry_type:
-               T_CLASS                 { $$.u.constant.value.lval = T_CLASS; }
-       |       T_INTERFACE             { $$.u.constant.value.lval = T_INTERFACE; }
+               T_CLASS                 {  $$.u.constant.value.lval = 0; }
+       |       T_ABSTRACT T_CLASS { $$.u.constant.value.lval = ZEND_ACC_ABSTRACT_CLASS; }
+       |       T_INTERFACE             { $$.u.constant.value.lval = ZEND_ACC_INTERFACE; }
 ;
 
 namespace_declaration_statement: