Skip to content

Commit

Permalink
Add support for interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
zsuraski committed Mar 5, 2003
1 parent e25dabc commit 26dd849
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 59 deletions.
3 changes: 3 additions & 0 deletions Zend/zend.h
Expand Up @@ -332,6 +332,9 @@ struct _zend_class_entry {
/* handlers */ /* handlers */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC); zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);


zend_class_entry **interfaces;
zend_uint num_interfaces;

/* old handlers */ /* old handlers */
#if 0 #if 0
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference); void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
Expand Down
30 changes: 20 additions & 10 deletions Zend/zend_builtin_functions.c
Expand Up @@ -590,7 +590,9 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
{ {
zval **obj, **class_name; zval **obj, **class_name;
char *lcname; char *lcname;
zend_class_entry *ce = NULL; zend_class_entry *instance_ce;
zend_class_entry **ce;
zend_bool retval;


if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &obj, &class_name)==FAILURE) { if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &obj, &class_name)==FAILURE) {
ZEND_WRONG_PARAM_COUNT(); ZEND_WRONG_PARAM_COUNT();
Expand All @@ -610,18 +612,26 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
lcname = estrndup(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name)); lcname = estrndup(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name));
zend_str_tolower(lcname, Z_STRLEN_PP(class_name)); zend_str_tolower(lcname, Z_STRLEN_PP(class_name));


if (only_subclass) if (zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(class_name)+1, (void **) &ce)==FAILURE) {
ce = Z_OBJCE_PP(obj)->parent; efree(lcname);
else retval = 0;
ce = Z_OBJCE_PP(obj); } else {
for (; ce != NULL; ce = ce->parent) { if (only_subclass) {
if ((ce->name_length == Z_STRLEN_PP(class_name)) && !memcmp(ce->name, lcname, ce->name_length)) { instance_ce = Z_OBJCE_PP(obj)->parent;
efree(lcname); } else {
RETURN_TRUE; instance_ce = Z_OBJCE_PP(obj);
}

if (instanceof_function(instance_ce, *ce TSRMLS_CC)) {
retval = 1;
} else {
retval = 0;
} }
} }

efree(lcname); efree(lcname);
RETURN_FALSE;
RETURN_BOOL(retval);
} }




Expand Down
103 changes: 83 additions & 20 deletions Zend/zend_compile.c
Expand Up @@ -377,20 +377,29 @@ void zend_do_echo(znode *arg TSRMLS_DC)


void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC) void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body TSRMLS_DC)
{ {
char *method_type;

if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
modifiers->u.constant.value.lval |= ZEND_ACC_ABSTRACT;
method_type = "Interface";
} else {
method_type = "Abstract";
}

if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) { if (modifiers->u.constant.value.lval & ZEND_ACC_ABSTRACT) {
if (body->u.constant.value.lval & ZEND_ACC_ABSTRACT) { if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);


opline->opcode = ZEND_RAISE_ABSTRACT_ERROR; opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
SET_UNUSED(opline->op1); SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2); SET_UNUSED(opline->op2);
} else { } else {
/* we had code in the function body */ /* we had code in the function body */
zend_error(E_COMPILE_ERROR, "Abstract function %s() cannot contain body", function_name->u.constant.value.str.val); zend_error(E_COMPILE_ERROR, "%s function %s::%s() cannot contain body", method_type, CG(active_class_entry)->name, function_name->u.constant.value.str.val);
} }
} else { } else {
if (body->u.constant.value.lval & ZEND_ACC_ABSTRACT) { if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
zend_error(E_COMPILE_ERROR, "Non-abstract method %s() must contain body", function_name->u.constant.value.str.val); zend_error(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
} }
} }
} }
Expand Down Expand Up @@ -665,11 +674,13 @@ zend_bool zend_is_function_or_method_call(znode *variable)
return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL)); return ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
} }



void zend_do_begin_import(TSRMLS_D) void zend_do_begin_import(TSRMLS_D)
{ {
zend_llist_init(&CG(import_commands), sizeof(zend_op), NULL, 0); zend_llist_init(&CG(import_commands), sizeof(zend_op), NULL, 0);
} }



void zend_do_import(int type, znode *what TSRMLS_DC) void zend_do_import(int type, znode *what TSRMLS_DC)
{ {
zend_op opline; zend_op opline;
Expand Down Expand Up @@ -700,11 +711,11 @@ void zend_do_import(int type, znode *what TSRMLS_DC)
zend_llist_add_element(&CG(import_commands), &opline); zend_llist_add_element(&CG(import_commands), &opline);
} }



void zend_do_end_import(znode *import_from TSRMLS_DC) void zend_do_end_import(znode *import_from TSRMLS_DC)
{ {
zend_llist_element *le; zend_llist_element *le;
zend_op *opline, *opline_ptr; zend_op *opline, *opline_ptr;



le = CG(import_commands).head; le = CG(import_commands).head;


Expand All @@ -719,7 +730,6 @@ void zend_do_end_import(znode *import_from TSRMLS_DC)
} }





void zend_do_begin_variable_parse(TSRMLS_D) void zend_do_begin_variable_parse(TSRMLS_D)
{ {
zend_llist fetch_list; zend_llist fetch_list;
Expand Down Expand Up @@ -933,12 +943,25 @@ int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier)
} }




void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC) void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC)
{ {
zend_op_array op_array; zend_op_array op_array;
char *name = function_name->u.constant.value.str.val; char *name = function_name->u.constant.value.str.val;
int name_len = function_name->u.constant.value.str.len; int name_len = function_name->u.constant.value.str.len;
int function_begin_line = function_token->u.opline_num; int function_begin_line = function_token->u.opline_num;
zend_uint fn_flags;

if (is_method) {
if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
if (!(fn_flags_znode->u.constant.value.lval & ZEND_ACC_PUBLIC)) {
zend_error(E_COMPILE_ERROR, "Access type for interface method %s::%s() must be omitted or declared public", CG(active_class_entry)->name, function_name->u.constant.value.str.val);
}
fn_flags_znode->u.constant.value.lval |= ZEND_ACC_ABSTRACT; /* propagates to the rest of the parser */
}
fn_flags = fn_flags_znode->u.constant.value.lval; /* must be done *after* the above check */
} else {
fn_flags = 0;
}


function_token->u.op_array = CG(active_op_array); function_token->u.op_array = CG(active_op_array);
zend_str_tolower(name, name_len); zend_str_tolower(name, name_len);
Expand Down Expand Up @@ -972,7 +995,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
&& (child_op_array == parent_op_array)) { && (child_op_array == parent_op_array)) {
zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array)); zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
} else { } else {
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s()", name); zend_error(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", CG(active_class_entry)->name, name);
} }
} }


Expand Down Expand Up @@ -1680,6 +1703,11 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro


void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
{ {
if ((ce->ce_flags & ZEND_ACC_INTERFACE)
&& !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
zend_error(E_ERROR, "Interface %s may not inherit from class (%s)", ce->name, parent_ce->name);
}

ce->parent = parent_ce; ce->parent = parent_ce;


/* Inherit properties */ /* Inherit properties */
Expand All @@ -1693,6 +1721,14 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
do_inherit_parent_constructor(ce); do_inherit_parent_constructor(ce);
} }



void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface)
{
zend_hash_merge(&ce->constants_table, &iface->constants_table, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0);
zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
}


static void create_class(HashTable *class_table, char *name, int name_length, zend_class_entry **ce TSRMLS_DC) static void create_class(HashTable *class_table, char *name, int name_length, zend_class_entry **ce TSRMLS_DC)
{ {
zend_class_entry *new_class_entry; zend_class_entry *new_class_entry;
Expand All @@ -1716,7 +1752,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze


#include "../TSRM/tsrm_strtok_r.h" #include "../TSRM/tsrm_strtok_r.h"


static int create_nested_class(HashTable *class_table, char *path, zend_class_entry *new_ce TSRMLS_DC) static zend_class_entry *create_nested_class(HashTable *class_table, char *path, zend_class_entry *new_ce TSRMLS_DC)
{ {
char *cur, *temp; char *cur, *temp;
char *last; char *last;
Expand Down Expand Up @@ -1749,9 +1785,9 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en
if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) { if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) {
new_ce->refcount--; new_ce->refcount--;
zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last); zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last);
return FAILURE; return NULL;
} }
return SUCCESS; return new_ce;
} }


ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time) ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time)
Expand Down Expand Up @@ -1786,13 +1822,13 @@ ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTa
} }




ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC) ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC)
{ {
zend_class_entry *ce, **pce; zend_class_entry *ce, **pce;


if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) { if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) {
zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val); zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
return FAILURE; return NULL;
} else { } else {
ce = *pce; ce = *pce;
} }
Expand All @@ -1803,13 +1839,13 @@ ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) { if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
ce->refcount--; ce->refcount--;
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val); zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
return FAILURE; return NULL;
} else { } else {
return SUCCESS; return ce;
} }
} }


ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC) ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC)
{ {
zend_class_entry *ce, **pce; zend_class_entry *ce, **pce;
int found_ce; int found_ce;
Expand All @@ -1818,7 +1854,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table,


if (found_ce == FAILURE) { if (found_ce == FAILURE) {
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name); zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name);
return FAILURE; return NULL;
} else { } else {
ce = *pce; ce = *pce;
} }
Expand All @@ -1840,9 +1876,9 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table,
zend_hash_destroy(&ce->properties_info); zend_hash_destroy(&ce->properties_info);
zend_hash_destroy(ce->static_members); zend_hash_destroy(ce->static_members);
zend_hash_destroy(&ce->constants_table); zend_hash_destroy(&ce->constants_table);
return FAILURE; return NULL;
} }
return SUCCESS; return ce;
} }




Expand Down Expand Up @@ -2157,9 +2193,13 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
new_class_entry->name = class_name->u.constant.value.str.val; new_class_entry->name = class_name->u.constant.value.str.val;
new_class_entry->name_length = class_name->u.constant.value.str.len; new_class_entry->name_length = class_name->u.constant.value.str.len;


new_class_entry->type = ZEND_USER_CLASS;
new_class_entry->parent = NULL; new_class_entry->parent = NULL;
new_class_entry->num_interfaces = 0;

zend_initialize_class_data(new_class_entry, 1 TSRMLS_CC); 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;
}


if (parent_class_name->op_type != IS_UNUSED) { if (parent_class_name->op_type != IS_UNUSED) {
doing_inheritance = 1; doing_inheritance = 1;
Expand All @@ -2186,15 +2226,34 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod


zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL); zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry; CG(active_class_entry) = new_class_entry;

opline->result.u.var = get_temporary_variable(CG(active_op_array));
opline->result.op_type = IS_CONST;
CG(implementing_class) = opline->result;
} }




void zend_do_end_class_declaration(znode *class_token TSRMLS_DC) void zend_do_end_class_declaration(znode *class_token TSRMLS_DC)
{ {
do_inherit_parent_constructor(CG(active_class_entry)); 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);
}
CG(active_class_entry) = NULL; CG(active_class_entry) = NULL;
} }



void zend_do_implements_interface(znode *interface_znode TSRMLS_DC)
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);

opline->opcode = ZEND_ADD_INTERFACE;
opline->op1 = CG(implementing_class);
opline->op2 = *interface_znode;
opline->extended_value = CG(active_class_entry)->num_interfaces++;
}


void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length) void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length)
{ {
char *prop_name; char *prop_name;
Expand All @@ -2219,6 +2278,10 @@ void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_ty
HashTable *target_symbol_table; HashTable *target_symbol_table;
zend_bool free_var_name = 0; zend_bool free_var_name = 0;


if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables");
}

if (access_type & ZEND_ACC_ABSTRACT) { if (access_type & ZEND_ACC_ABSTRACT) {
zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract"); zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract");
} }
Expand Down
11 changes: 8 additions & 3 deletions Zend/zend_compile.h
Expand Up @@ -92,6 +92,7 @@ typedef struct _zend_brk_cont_element {
#define ZEND_ACC_STATIC 0x01 #define ZEND_ACC_STATIC 0x01
#define ZEND_ACC_ABSTRACT 0x02 #define ZEND_ACC_ABSTRACT 0x02
#define ZEND_ACC_FINAL 0x04 #define ZEND_ACC_FINAL 0x04
#define ZEND_ACC_INTERFACE 0x08


/* The order of those must be kept - public < protected < private */ /* The order of those must be kept - public < protected < private */
#define ZEND_ACC_PUBLIC 0x10 #define ZEND_ACC_PUBLIC 0x10
Expand Down Expand Up @@ -308,7 +309,7 @@ void zend_do_add_string(znode *result, znode *op1, znode *op2 TSRMLS_DC);
void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC); void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC);


int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier); int zend_do_verify_access_types(znode *current_access_type, znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, zend_uint fn_flags TSRMLS_DC); void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(znode *function_token TSRMLS_DC); void zend_do_end_function_declaration(znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC); void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initialization, zend_uchar pass_type TSRMLS_DC);
int zend_do_begin_function_call(znode *function_name TSRMLS_DC); int zend_do_begin_function_call(znode *function_name TSRMLS_DC);
Expand All @@ -326,10 +327,12 @@ void zend_do_end_catch(znode *try_token TSRMLS_DC);
void zend_do_throw(znode *expr TSRMLS_DC); void zend_do_throw(znode *expr TSRMLS_DC);


ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time); ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTable *class_table, int compile_time);
ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC); ZEND_API zend_class_entry *do_bind_class(zend_op *opline, HashTable *function_table, HashTable *class_table TSRMLS_DC);
ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC); ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *function_table, HashTable *class_table, zend_class_entry *parent_ce TSRMLS_DC);
void zend_do_implements_interface(znode *interface_znode TSRMLS_DC);


void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce); void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce);
void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
void zend_do_early_binding(TSRMLS_D); void zend_do_early_binding(TSRMLS_D);


void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC); void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC);
Expand Down Expand Up @@ -658,6 +661,8 @@ int zendlex(znode *zendlval TSRMLS_DC);


#define ZEND_START_NAMESPACE 143 #define ZEND_START_NAMESPACE 143


#define ZEND_ADD_INTERFACE 144

/* end of block */ /* end of block */




Expand Down

0 comments on commit 26dd849

Please sign in to comment.