diff options
author | Zeev Suraski <zeev@php.net> | 2003-03-06 22:53:23 +0000 |
---|---|---|
committer | Zeev Suraski <zeev@php.net> | 2003-03-06 22:53:23 +0000 |
commit | 0338111950edcec427cfa2f1610dd6efcd43a14c (patch) | |
tree | fcbc0fbbfed58389d438a29a51a16ecf22a90780 | |
parent | af4aa97d1ec853836f70601cb9666794476cd140 (diff) | |
download | php-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.c | 21 | ||||
-rw-r--r-- | Zend/zend_compile.h | 22 | ||||
-rw-r--r-- | Zend/zend_execute.c | 18 | ||||
-rw-r--r-- | Zend/zend_language_parser.y | 7 |
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: |