]> granicus.if.org Git - php/commitdiff
Expand Interface C API.
authorMarcus Boerger <helly@php.net>
Wed, 22 Oct 2003 19:59:58 +0000 (19:59 +0000)
committerMarcus Boerger <helly@php.net>
Wed, 22 Oct 2003 19:59:58 +0000 (19:59 +0000)
In short: zend_class_entry->interface_gets_implemented()  allows to modify
the class entry of a class when an interface gets implemented.

Zend/zend.h
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c

index 4317f7537309fd347aa491ef79c8fe0a86ed88d7..f63ab21a2a266dede49585abba27608396f9738b 100644 (file)
@@ -338,6 +338,7 @@ struct _zend_class_entry {
        /* handlers */
        zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
        zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object TSRMLS_DC);
+       int (*interface_gets_implemented)(zend_class_entry *iface, zend_class_entry *class_type TSRMLS_DC); /* a class implements this interface */
 
        zend_class_entry **interfaces;
        zend_uint num_interfaces;
index d5d8676292dd08ffeabe0f444cbc9262ee9bbe66..f9a868ddda687bcdf014d9e7fb1d5b0dd9c01a26 100644 (file)
@@ -1419,6 +1419,26 @@ int zend_next_free_module(void)
        return ++module_count;
 }
 
+static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, zend_uint ce_flags TSRMLS_DC)
+{
+       zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
+       char *lowercase_name = malloc(orig_class_entry->name_length + 1);
+       *class_entry = *orig_class_entry;
+
+       class_entry->type = ZEND_INTERNAL_CLASS;
+       zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
+       class_entry->ce_flags = ce_flags;
+
+       if (class_entry->builtin_functions) {
+               zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
+       }
+
+       zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
+       zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
+       free(lowercase_name);
+       return class_entry;
+}
+
 /* If parent_ce is not NULL then it inherits from parent_ce
  * If parent_ce is NULL and parent_name isn't then it looks for the parent and inherits from it
  * If both parent_ce and parent_name are NULL it does a regular class registration
@@ -1440,7 +1460,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla
        register_class = zend_register_internal_class(class_entry TSRMLS_CC);
 
        if (parent_ce) {
-               zend_do_inheritance(register_class, parent_ce);
+               zend_do_inheritance(register_class, parent_ce TSRMLS_CC);
        }
        return register_class;
 }
@@ -1460,28 +1480,21 @@ ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int
        while (num_interfaces--) {
                interface_entry = va_arg(interface_list, zend_class_entry *);
                class_entry->interfaces[class_entry->num_interfaces++] = interface_entry;
-               zend_do_implement_interface(class_entry, interface_entry);
+               zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC);
        }
        va_end(interface_list);
 }
 
+/* A class that contains at least one abstract method automatically becomes an abstract class.
+ */
 ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry TSRMLS_DC)
 {
-       zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
-       char *lowercase_name = malloc(orig_class_entry->name_length + 1);
-       *class_entry = *orig_class_entry;
-
-       class_entry->type = ZEND_INTERNAL_CLASS;
-       zend_initialize_class_data(class_entry, 0 TSRMLS_CC);
-
-       if (class_entry->builtin_functions) {
-               zend_register_functions(class_entry, class_entry->builtin_functions, &class_entry->function_table, MODULE_PERSISTENT TSRMLS_CC);
-       }
+       return do_register_internal_class(orig_class_entry, 0 TSRMLS_CC);
+}
 
-       zend_str_tolower_copy(lowercase_name, orig_class_entry->name, class_entry->name_length);
-       zend_hash_update(CG(class_table), lowercase_name, class_entry->name_length+1, &class_entry, sizeof(zend_class_entry *), NULL);
-       free(lowercase_name);
-       return class_entry;
+ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC)
+{
+       return do_register_internal_class(orig_class_entry, ZEND_ACC_ABSTRACT|ZEND_ACC_INTERFACE TSRMLS_CC);
 }
 
 ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length,
index d7b9a443901a775bd57e81b1e0442ca897a83ad6..0b079bbfb8aba5fcbe2b32e863e8982e642390f5 100644 (file)
@@ -121,6 +121,7 @@ typedef struct _zend_function_entry {
                class_container.destructor = NULL;                                              \
                class_container.clone = NULL;                                                   \
                class_container.create_object = NULL;                                   \
+               class_container.interface_gets_implemented = NULL;              \
                class_container.__call = handle_fcall;  \
                class_container.__get = handle_propget; \
                class_container.__set = handle_propset; \
@@ -160,6 +161,7 @@ ZEND_API int zend_register_module(zend_module_entry *module_entry);
 
 ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry TSRMLS_DC);
 ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce, char *parent_name TSRMLS_DC);
+ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry TSRMLS_DC);
 ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...);
 
 ZEND_API int zend_disable_function(char *function_name, uint function_name_length TSRMLS_DC);
index f0e73b3e07a690a14f0460296366a4d96e0bc736..bd3d16c0b56e11d1f7e124a7958200357055469d 100644 (file)
@@ -1832,18 +1832,45 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro
 }
 
 
-ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *ce2)
+static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC)
 {
-       int num = ce2->num_interfaces;
+       if (!(ce->ce_flags & ZEND_ACC_ABSTRACT) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
+               zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name, iface->name);
+       }
+}
 
-       if (num) {
+
+ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC)
+{
+       /* expects interface to be contained in ce's interface list already */
+       int i, ce_num, if_num = iface->num_interfaces;
+       zend_class_entry *entry;
+
+       if (if_num) {
+               ce_num = ce->num_interfaces;
                if (ce->type == ZEND_INTERNAL_CLASS) {
-                       ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce->num_interfaces + num));
+                       ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
                } else {
-                       ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce->num_interfaces + num));
+                       ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
+               }
+
+               /* only have every interface ones - this holds for the list we append too, what makes the test a bit faster */
+               while (if_num--) {
+                       entry = iface->interfaces[if_num];
+                       for (i = 0; i < ce_num; ++i) {
+                               if (ce->interfaces[i] == entry) {
+                                       break;
+                               }
+                       }
+                       if (i == ce_num) {
+                               ce->interfaces[ce->num_interfaces++] = entry;
+                       }
+               }
+
+               /* and now call the implementing handlers */
+               while (ce_num < ce->num_interfaces) {
+                       do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
                }
-               memcpy(&ce->interfaces[ce->num_interfaces], ce2->interfaces, num * sizeof(zend_class_entry*));
-               ce->num_interfaces += num;
        }
 }
 
@@ -1855,7 +1882,7 @@ static void inherit_sttaic_prop(zval **p)
 }
 
 
-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 TSRMLS_DC)
 {
        if ((ce->ce_flags & ZEND_ACC_INTERFACE)
                && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
@@ -1867,7 +1894,7 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
 
        ce->parent = parent_ce;
        /* Inherit interfaces */
-       zend_do_inherit_interfaces(ce, parent_ce);
+       zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
 
        /* Inherit properties */
        zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, NULL, sizeof(zval *), 0);
@@ -1880,12 +1907,13 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce)
 }
 
 
-ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface)
+ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC)
 {
        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);
 
-       zend_do_inherit_interfaces(ce, iface);
+       do_implement_interface(ce, iface TSRMLS_CC);
+       zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
 }
 
 
@@ -1955,7 +1983,7 @@ ZEND_API zend_class_entry *do_bind_inherited_class(zend_op *opline, HashTable *f
                ce = *pce;
        }
 
-       zend_do_inheritance(ce, parent_ce);
+       zend_do_inheritance(ce, parent_ce TSRMLS_CC);
 
        ce->refcount++;
 
index 16c0141f173a2de1b46d2b609132ec8a3f385de9..43f95240250e5c65047ba772c2a79c181aff84cd 100644 (file)
@@ -356,11 +356,11 @@ 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 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);
-ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *ce2);
-ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface);
+ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC);
+ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface 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 TSRMLS_DC);
 void zend_do_early_binding(TSRMLS_D);
 
 void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC);
index fae7e65de306df913a269c350e2acbad3d4a4392..1bbd28108dab9dc72338e1d53215d8acc135e771 100644 (file)
@@ -4010,7 +4010,7 @@ int zend_add_interface_handler(ZEND_OPCODE_HANDLER_ARGS)
 
        ce->interfaces[EX(opline)->extended_value] = iface;
 
-       zend_do_implement_interface(ce, iface);
+       zend_do_implement_interface(ce, iface TSRMLS_CC);
 
        NEXT_OPCODE();
 }