mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
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:
parent
af4aa97d1e
commit
0338111950
4 changed files with 50 additions and 18 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue