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 :)
This commit is contained in:
Zeev Suraski 2003-03-06 22:53:23 +00:00
parent af4aa97d1e
commit 0338111950
4 changed files with 50 additions and 18 deletions

View 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;
}

View file

@ -93,15 +93,16 @@ typedef struct _zend_brk_cont_element {
#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 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;
}
/*

View 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: