summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeev Suraski <zeev@php.net>2003-03-06 22:53:23 +0000
committerZeev Suraski <zeev@php.net>2003-03-06 22:53:23 +0000
commit0338111950edcec427cfa2f1610dd6efcd43a14c (patch)
treefcbc0fbbfed58389d438a29a51a16ecf22a90780
parentaf4aa97d1ec853836f70601cb9666794476cd140 (diff)
downloadphp-git-0338111950edcec427cfa2f1610dd6efcd43a14c.tar.gz
Require abstract classes to be explicitly declared 'abstract', in order 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 :)
-rw-r--r--Zend/zend_compile.c21
-rw-r--r--Zend/zend_compile.h22
-rw-r--r--Zend/zend_execute.c18
-rw-r--r--Zend/zend_language_parser.y7
4 files changed, 50 insertions, 18 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index c609fa28a1..1f89b7e0af 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -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;
}
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 112e0ebb9e..b4d49b2920 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -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 */
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 46897d0967..f0a015293b 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -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;
}
/*
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index c25ce39f08..d81f62e908 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -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: