/* 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;
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
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;
}
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,
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; \
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);
}
-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;
}
}
}
-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)) {
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);
}
-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);
}
ce = *pce;
}
- zend_do_inheritance(ce, parent_ce);
+ zend_do_inheritance(ce, parent_ce TSRMLS_CC);
ce->refcount++;
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);
ce->interfaces[EX(opline)->extended_value] = iface;
- zend_do_implement_interface(ce, iface);
+ zend_do_implement_interface(ce, iface TSRMLS_CC);
NEXT_OPCODE();
}