]> granicus.if.org Git - php/commitdiff
Add support for interfaces
authorZeev Suraski <zeev@php.net>
Wed, 5 Mar 2003 11:14:44 +0000 (11:14 +0000)
committerZeev Suraski <zeev@php.net>
Wed, 5 Mar 2003 11:14:44 +0000 (11:14 +0000)
Zend/zend.h
Zend/zend_builtin_functions.c
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_globals.h
Zend/zend_language_parser.y
Zend/zend_language_scanner.l
Zend/zend_opcode.c
Zend/zend_operators.c
Zend/zend_operators.h

index f8111bb74b6df906c21cc83a9a1fe4cfe7f1a220..3cf15371f0ced455bff619e4b1c92493e3c76592 100644 (file)
@@ -332,6 +332,9 @@ struct _zend_class_entry {
        /* handlers */
        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
 
+       zend_class_entry **interfaces;
+       zend_uint num_interfaces;
+
        /* old handlers */
 #if 0
        void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
index 571b591fd63dc24d87aa24147fa84a41f13a3ed7..8d889ff4568de192c9ba069486816d113721d108 100644 (file)
@@ -590,7 +590,9 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
 {
        zval **obj, **class_name;
        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) {
                ZEND_WRONG_PARAM_COUNT();
@@ -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));
        zend_str_tolower(lcname, Z_STRLEN_PP(class_name));
 
-       if (only_subclass)
-               ce = Z_OBJCE_PP(obj)->parent;
-       else
-               ce = Z_OBJCE_PP(obj);
-       for (; ce != NULL; ce = ce->parent) {
-               if ((ce->name_length == Z_STRLEN_PP(class_name)) && !memcmp(ce->name, lcname, ce->name_length)) {
-                       efree(lcname);
-                       RETURN_TRUE;
+       if (zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(class_name)+1, (void **) &ce)==FAILURE) {
+               efree(lcname);
+               retval = 0;
+       } else {
+               if (only_subclass) {
+                       instance_ce = Z_OBJCE_PP(obj)->parent;
+               } else {
+                       instance_ce = Z_OBJCE_PP(obj);
+               }
+
+               if (instanceof_function(instance_ce, *ce TSRMLS_CC)) {
+                       retval = 1;
+               } else {
+                       retval = 0;
                }
        }
+
        efree(lcname);
-       RETURN_FALSE;
+
+       RETURN_BOOL(retval);
 }
 
 
index 1d05de1edaceb864aa24bf44260578958820cf3a..1840f6fbbb0c4cc3157d6d8dfc1820e52ac344dd 100644 (file)
@@ -377,8 +377,17 @@ void zend_do_echo(znode *arg 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 (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);
 
                        opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
@@ -386,11 +395,11 @@ void zend_do_abstract_method(znode *function_name, znode *modifiers, znode *body
                        SET_UNUSED(opline->op2);
                } else {
                        /* 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 {
-               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);
+               if (body->u.constant.value.lval == ZEND_ACC_ABSTRACT) {
+                       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);
                }
        }
 }
@@ -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));
 }
 
+
 void zend_do_begin_import(TSRMLS_D)
 {
        zend_llist_init(&CG(import_commands), sizeof(zend_op), NULL, 0);
 }
 
+
 void zend_do_import(int type, znode *what TSRMLS_DC)
 {
        zend_op opline;
@@ -700,11 +711,11 @@ void zend_do_import(int type, znode *what TSRMLS_DC)
        zend_llist_add_element(&CG(import_commands), &opline);
 }
 
+
 void zend_do_end_import(znode *import_from TSRMLS_DC)
 {
        zend_llist_element *le;
        zend_op *opline, *opline_ptr;
-
        
        le = CG(import_commands).head;
 
@@ -719,7 +730,6 @@ void zend_do_end_import(znode *import_from TSRMLS_DC)
 }
 
 
-
 void zend_do_begin_variable_parse(TSRMLS_D)
 {
        zend_llist fetch_list;
@@ -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;
        char *name = function_name->u.constant.value.str.val;
        int name_len = function_name->u.constant.value.str.len;
        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);
        zend_str_tolower(name, name_len);
@@ -972,7 +995,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
                                        && (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));
                        } 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);
                        }
                }
 
@@ -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)
 {
+       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;
 
        /* Inherit properties */
@@ -1693,6 +1721,14 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_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)
 {
        zend_class_entry *new_class_entry;
@@ -1716,7 +1752,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
 
 #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 *last;
@@ -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) {
                new_ce->refcount--;
                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)
@@ -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;
 
        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);
-               return FAILURE;
+               return NULL;
        } else {
                ce = *pce;
        }
@@ -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) {
                ce->refcount--;
                zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
-               return FAILURE;
+               return NULL;
        } 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;
        int found_ce;
@@ -1818,7 +1854,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table,
 
        if (found_ce == FAILURE) {
                zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name);
-               return FAILURE;
+               return NULL;
        } else {
                ce = *pce;
        }
@@ -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->static_members);
                zend_hash_destroy(&ce->constants_table);
-               return FAILURE;
+               return NULL;
        }
-       return SUCCESS;
+       return ce;
 }
 
 
@@ -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_length = class_name->u.constant.value.str.len;
 
-       new_class_entry->type = ZEND_USER_CLASS;
        new_class_entry->parent = NULL;
+       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;
+       }
 
        if (parent_class_name->op_type != IS_UNUSED) {
                doing_inheritance = 1;
@@ -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);
        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)
 {
        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;
 }
 
+
+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)
 {
        char *prop_name;
@@ -2219,6 +2278,10 @@ void zend_do_declare_property(znode *var_name, znode *value, zend_uint access_ty
        HashTable *target_symbol_table;
        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) {
                zend_error(E_COMPILE_ERROR, "Properties cannot be declared abstract");
        }
index 70f9ead01f1cb433b7bc889f793cfd47aebdcfff..f24e14b8c837011e545edccefd42baeafdbb16c6 100644 (file)
@@ -92,6 +92,7 @@ typedef struct _zend_brk_cont_element {
 #define ZEND_ACC_STATIC                0x01
 #define ZEND_ACC_ABSTRACT      0x02
 #define ZEND_ACC_FINAL         0x04
+#define ZEND_ACC_INTERFACE     0x08
 
 /* The order of those must be kept - public < protected < private */
 #define ZEND_ACC_PUBLIC                0x10
@@ -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);
 
 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_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);
@@ -326,10 +327,12 @@ void zend_do_end_catch(znode *try_token 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_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_class(zend_op *opline, HashTable *function_table, HashTable *class_table 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_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
 void zend_do_early_binding(TSRMLS_D);
 
 void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC);
@@ -658,6 +661,8 @@ int zendlex(znode *zendlval TSRMLS_DC);
 
 #define ZEND_START_NAMESPACE           143
 
+#define ZEND_ADD_INTERFACE                     144
+
 /* end of block */
 
 
index 44f9a43d006dc981dd9c5a59f8acc51eb945dc49..39a7b01b3d69650ed54696e61d9e125312fb8f41 100644 (file)
@@ -3113,7 +3113,14 @@ 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) {
-               zend_error(E_ERROR, "Cannot instantiate abstract class %s", EX_T(EX(opline)->op1.u.var).EA.class_entry->name);
+               char *class_type;
+
+               if (EX_T(EX(opline)->op1.u.var).EA.class_entry->ce_flags & ZEND_ACC_INTERFACE) {
+                       class_type = "interface";
+               } else {
+                       class_type = "abstract_class";
+               }
+               zend_error(E_ERROR, "Cannot instantiate %s %s", class_type, EX_T(EX(opline)->op1.u.var).EA.class_entry->name);
        }
        EX_T(EX(opline)->result.u.var).var.ptr_ptr = &EX_T(EX(opline)->result.u.var).var.ptr;
        ALLOC_ZVAL(EX_T(EX(opline)->result.u.var).var.ptr);
@@ -3875,14 +3882,14 @@ int zend_ext_fcall_end_handler(ZEND_OPCODE_HANDLER_ARGS)
 
 int zend_declare_class_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
-       do_bind_class(EX(opline), EG(function_table), EG(class_table) TSRMLS_CC);
+       EX_T(EX(opline)->result.u.var).EA.class_entry = do_bind_class(EX(opline), EG(function_table), EG(class_table) TSRMLS_CC);
        NEXT_OPCODE();
 }
 
 
 int zend_declare_inherited_class_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
-       do_bind_inherited_class(EX(opline), EG(function_table), EG(class_table), EX_T(EX(opline)->extended_value).EA.class_entry TSRMLS_CC);
+       EX_T(EX(opline)->result.u.var).EA.class_entry = do_bind_inherited_class(EX(opline), EG(function_table), EG(class_table), EX_T(EX(opline)->extended_value).EA.class_entry TSRMLS_CC);
        NEXT_OPCODE();
 }
 
@@ -3909,8 +3916,14 @@ int zend_ticks_handler(ZEND_OPCODE_HANDLER_ARGS)
 int zend_instanceof_handler(ZEND_OPCODE_HANDLER_ARGS)
 {
        zval *expr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
-       instanceof_function(&EX_T(EX(opline)->result.u.var).tmp_var, expr,
-                                                EX_T(EX(opline)->op2.u.var).EA.class_entry TSRMLS_CC);
+       zend_bool result;
+
+       if (Z_TYPE_P(expr) == IS_OBJECT) {
+               result = instanceof_function(Z_OBJCE_P(expr), EX_T(EX(opline)->op2.u.var).EA.class_entry TSRMLS_CC);
+       } else {
+               result = 0;
+       }
+       ZVAL_BOOL(&EX_T(EX(opline)->result.u.var).tmp_var, result);
        FREE_OP(EX(Ts), &EX(opline)->op1, EG(free_op1));
        NEXT_OPCODE();
 }
@@ -3951,6 +3964,23 @@ int zend_start_namespace_handler(ZEND_OPCODE_HANDLER_ARGS)
        NEXT_OPCODE();
 }
 
+
+int zend_add_interface_handler(ZEND_OPCODE_HANDLER_ARGS)
+{
+       zend_class_entry *ce = EX_T(EX(opline)->op1.u.var).EA.class_entry;
+       zend_class_entry *iface = EX_T(EX(opline)->op2.u.var).EA.class_entry;
+
+       if (!(iface->ce_flags & ZEND_ACC_INTERFACE)) {
+               zend_error(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name);
+       }
+
+       ce->interfaces[EX(opline)->extended_value] = iface;
+
+       zend_do_implement_interface(ce, iface);
+
+       NEXT_OPCODE();
+}
+
 void zend_init_opcodes_handlers()
 {
        zend_opcode_handlers[ZEND_NOP] = zend_nop_handler;
@@ -4126,6 +4156,8 @@ void zend_init_opcodes_handlers()
 
        zend_opcode_handlers[ZEND_RAISE_ABSTRACT_ERROR] = zend_raise_abstract_error_handler;
        zend_opcode_handlers[ZEND_START_NAMESPACE] = zend_start_namespace_handler;
+
+       zend_opcode_handlers[ZEND_ADD_INTERFACE] = zend_add_interface_handler;
 }
 
 /*
index 016c935cefcb7658d80c12a558ada6907684b15e..ac335fc47326f87b742fd23c67e224fc58a6e4e3 100644 (file)
@@ -127,6 +127,7 @@ struct _zend_compiler_globals {
        zend_bool increment_lineno;
 
        zend_llist import_commands;
+       znode implementing_class;
 
        zend_uint access_type;
 };
index 7accb8e06977f46d2a8bddac7ae0420b1730cf74..31506e11dbb768e5bd519cc8fe0f0f830c3394ec 100644 (file)
 %token T_ISSET
 %token T_EMPTY
 %token T_CLASS
+%token T_INTERFACE
 %token T_EXTENDS
+%token T_IMPLEMENTS
 %token T_OBJECT_OPERATOR
 %token T_DOUBLE_ARROW
 %token T_LIST
@@ -214,7 +216,7 @@ unticked_statement:
        |       T_DECLARE { $1.u.opline_num = get_next_op_number(CG(active_op_array)); zend_do_declare_begin(TSRMLS_C); } '(' declare_list ')' declare_statement { zend_do_declare_end(&$1 TSRMLS_CC); }
        |       ';'             /* empty statement */
        |       T_TRY { zend_do_try(&$1 TSRMLS_CC); } '{' inner_statement_list '}'
-               T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+               T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$8, &$9, 1 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
                additional_catches
        |       T_THROW expr ';' { zend_do_throw(&$2 TSRMLS_CC); }
        |       T_IMPORT { zend_do_begin_import(TSRMLS_C); } import_rule T_FROM import_namespace { zend_do_end_import(&$5 TSRMLS_CC); } ';'
@@ -246,8 +248,8 @@ additional_catches:
 ;
 
 non_empty_additional_catches:
-               non_empty_additional_catches T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
-       |       T_CATCH '(' catch_class_entry T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+               non_empty_additional_catches T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$2, &$4, &$5, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$2 TSRMLS_CC); }
+       |       T_CATCH '(' fully_qualified_class_name T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$4, 0 TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
 ;
 
 
@@ -282,12 +284,23 @@ is_reference:
 
 
 unticked_function_declaration_statement:
-               T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, 0 TSRMLS_CC); }
+               T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $3.op_type, NULL TSRMLS_CC); }
                        '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
 ;
 
 unticked_class_declaration_statement:
-               T_CLASS T_STRING extends_from '{' { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } class_statement_list '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
+               class_entry_type T_STRING extends_from
+                       { zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); } 
+                       implements_list
+                       '{'
+                               class_statement_list
+                       '}' { zend_do_end_class_declaration(&$1 TSRMLS_CC); }
+;
+
+
+class_entry_type:
+               T_CLASS                 { $$.u.constant.value.lval = T_CLASS; }
+       |       T_INTERFACE             { $$.u.constant.value.lval = T_INTERFACE; }
 ;
 
 namespace_declaration_statement:
@@ -324,12 +337,17 @@ namespace_const_declaration:
 
 extends_from:
                /* empty */                                     { $$.op_type = IS_UNUSED; }
-       |       T_EXTENDS catch_class_entry     { $$ = $2; }
+       |       T_EXTENDS fully_qualified_class_name    { $$ = $2; }
+;
+
+implements_list:
+               /* empty */
+       |       T_IMPLEMENTS interface_list
 ;
 
-declaration_class_name:
-               namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class_name(&$$, &$1, &$3, 0 TSRMLS_CC); }
-       |       
+interface_list:
+               fully_qualified_class_name                      { zend_do_implements_interface(&$1 TSRMLS_CC); }
+       |       interface_list ',' fully_qualified_class_name { zend_do_implements_interface(&$3 TSRMLS_CC); }
 ;
 
 foreach_optional_arg:
@@ -479,7 +497,7 @@ class_statement_list:
 class_statement:
                variable_modifiers { CG(access_type) = $1.u.constant.value.lval; } class_variable_declaration ';'
        |       class_constant_declaration ';'
-       |       method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, $1.u.constant.value.lval TSRMLS_CC); } '(' 
+       |       method_modifiers T_FUNCTION { $2.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $4.op_type, &$1 TSRMLS_CC); } '(' 
                        parameter_list ')' method_body { zend_do_abstract_method(&$5, &$1, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
 ;
 
@@ -629,7 +647,7 @@ parse_class_entry:
        |       T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, NULL, NULL TSRMLS_CC);  }
 ;
 
-catch_class_entry:
+fully_qualified_class_name:
                namespace_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { do_fetch_class(&$$, &$1, &$3 TSRMLS_CC); }
        |       T_STRING { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); }
  ;
index e062689b97ca94ee74e7a56bfb7acb47f0d846e2..61025d507da83582daabd9ff79a7e46b0f4abd8c 100644 (file)
@@ -614,10 +614,18 @@ NAMESPACE_NAME ({LABEL}":")+{LABEL}
        return T_CLASS;
 }
 
+<ST_IN_SCRIPTING>"interface" {
+       return T_INTERFACE;
+}
+
 <ST_IN_SCRIPTING>"extends" {
        return T_EXTENDS;
 }
 
+<ST_IN_SCRIPTING>"implements" {
+       return T_IMPLEMENTS;
+}
+
 <ST_IN_SCRIPTING>"namespace" {
        return T_NAMESPACE;
 }
index 334788a908b004a11c1d8576b5e9aeb11702a1fe..2611996d91c6031fbfe68274e07920e3af778f54 100644 (file)
@@ -154,6 +154,9 @@ ZEND_API void destroy_zend_class(zend_class_entry **pce)
                        FREE_HASHTABLE(ce->static_members);
                        zend_hash_destroy(&ce->constants_table);
                        zend_hash_destroy(&ce->class_table);
+                       if (ce->num_interfaces > 0) {
+                               efree(ce->interfaces);
+                       }
                        efree(ce);
                        break;
                case ZEND_INTERNAL_CLASS:
index 5374bfb4e7dca10f04d84d440ae48d6411f14aa4..5a216afc930721220740e408a2a2bae010a1e200 100644 (file)
@@ -1362,19 +1362,24 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR
 }
 
 
-ZEND_API int instanceof_function(zval *result, zval *op1, zend_class_entry *class TSRMLS_DC)
+ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC)
 {
-       if (Z_TYPE_P(op1) == IS_OBJECT) {
-               zend_class_entry *ce;
-               for (ce = Z_OBJCE_P(op1); ce != NULL; ce = ce->parent) {
-                       if (ce == class) {
-                               ZVAL_BOOL(result, 1);
-                               return SUCCESS;
+       zend_uint i;
+
+       while (instance_ce) {
+               if (instance_ce == ce) {
+                       return 1;
+               }
+               for (i=0; i<instance_ce->num_interfaces; i++) {
+
+                       if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
+                               return 1;
                        }
                }
+               instance_ce = instance_ce->parent;
        }
-       ZVAL_BOOL(result, 0);
-       return SUCCESS;
+
+       return 0;
 }
 
 #define LOWER_CASE 1
index 9320ab9b2134d5c93f6d440e744a1fbcfc88bf0f..b5edcdfb859c0fa6db723113ec4635f9745dc109 100644 (file)
@@ -59,7 +59,7 @@ ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
 ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
 ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC);
 
-ZEND_API int instanceof_function(zval *result, zval *op1, zend_class_entry *ce TSRMLS_DC);
+ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC);
 
 static inline zend_bool is_numeric_string(char *str, int length, long *lval, double *dval, zend_bool allow_errors)
 {