Permalink
Browse files

Require abstract classes to be explicitly declared 'abstract', in ord…

…er to

avoid making developers traverse the entire class/interface hierarchy
before they can figure out whether a class is instantiable
(ok, so it makes sense :)
  • Loading branch information...
zsuraski committed Mar 6, 2003
1 parent af4aa97 commit 0338111950edcec427cfa2f1610dd6efcd43a14c
Showing with 50 additions and 18 deletions.
  1. +17 −4 Zend/zend_compile.c
  2. +12 −10 Zend/zend_compile.h
  3. +17 −1 Zend/zend_execute.c
  4. +4 −3 Zend/zend_language_parser.y
View
@@ -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;
}
View
@@ -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 */
View
@@ -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;
}
/*
@@ -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:

0 comments on commit 0338111

Please sign in to comment.