Permalink
Browse files

Add new interface ArrayAccess to use objects as Arrays

  • Loading branch information...
1 parent bc4d008 commit 4dba05d9cc5bf3a03915eed4ec3f72621df6df26 Marcus Boerger committed Nov 24, 2003
View
@@ -920,13 +920,17 @@ static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2,
}
break;
case IS_OBJECT:
- if (type == BP_VAR_R) {
+ if (type == BP_VAR_R || type == BP_VAR_RW) {
if (!Z_OBJ_HT_P(container)->read_dimension) {
zend_error(E_ERROR, "Cannot use object as array");
} else {
zval *dim = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R);
zval *overloaded_result = Z_OBJ_HT_P(container)->read_dimension(container, dim TSRMLS_CC);
+ if (type == BP_VAR_RW && !overloaded_result->is_ref) {
+ zend_error(E_ERROR, "Objects used as arrays in post/pre increment/decrement must return values by reference");
+ }
+
*retval = &overloaded_result;
AI_USE_PTR(T(result->u.var).var);
FREE_OP(Ts, op2, EG(free_op2));
View
@@ -25,6 +25,7 @@
zend_class_entry *zend_ce_traversable;
zend_class_entry *zend_ce_aggregate;
zend_class_entry *zend_ce_iterator;
+zend_class_entry *zend_ce_arrayaccess;
/* {{{ zend_call_method
Only returns the returned zval if retval_ptr != NULL */
@@ -344,6 +345,13 @@ static int zend_implement_iterator(zend_class_entry *interface, zend_class_entry
}
/* }}} */
+/* {{{ zend_implement_arrayaccess */
+static int zend_implement_arrayaccess(zend_class_entry *interface, zend_class_entry *class_type TSRMLS_DC)
+{
+ return SUCCESS;
+}
+/* }}}*/
+
/* {{{ function tables */
zend_function_entry zend_funcs_aggregate[] = {
ZEND_ABSTRACT_ME(iterator, getIterator, NULL)
@@ -360,6 +368,26 @@ zend_function_entry zend_funcs_iterator[] = {
};
zend_function_entry *zend_funcs_traversable = NULL;
+
+static
+ZEND_BEGIN_ARG_INFO(arginfo_arrayaccess_offset, 0)
+ ZEND_ARG_INFO(0, offset)
+ZEND_END_ARG_INFO();
+
+static
+ZEND_BEGIN_ARG_INFO(arginfo_arrayaccess_offset_value, 0)
+ ZEND_ARG_INFO(0, offset)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO();
+
+zend_function_entry zend_funcs_arrayaccess[] = {
+ ZEND_ABSTRACT_ME(arrayaccess, offsetExists, arginfo_arrayaccess_offset)
+ ZEND_ABSTRACT_ME(arrayaccess, offsetGet, arginfo_arrayaccess_offset)
+ ZEND_ABSTRACT_ME(arrayaccess, offsetSet, arginfo_arrayaccess_offset_value)
+ ZEND_ABSTRACT_ME(arrayaccess, offsetUnset, arginfo_arrayaccess_offset)
+ {NULL, NULL, NULL}
+};
+
/* }}} */
#define REGISTER_ITERATOR_INTERFACE(class_name, class_name_str) \
@@ -383,6 +411,8 @@ ZEND_API void zend_register_interfaces(TSRMLS_D)
REGISTER_ITERATOR_INTERFACE(iterator, Iterator);
REGISTER_ITERATOR_IMPLEMENT(iterator, traversable);
+
+ REGISTER_ITERATOR_INTERFACE(arrayaccess, ArrayAccess);
}
/* }}} */
View
@@ -24,6 +24,7 @@
ZEND_API zend_class_entry *zend_ce_traversable;
ZEND_API zend_class_entry *zend_ce_aggregate;
ZEND_API zend_class_entry *zend_ce_iterator;
+ZEND_API zend_class_entry *zend_ce_arrayaccess;
ZEND_API zval* zend_call_method(zval **object_pp, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int function_name_len, zval **retval_ptr_ptr, int param_count, zval* arg1, zval* arg2 TSRMLS_DC);
@@ -26,6 +26,7 @@
#include "zend_objects.h"
#include "zend_objects_API.h"
#include "zend_object_handlers.h"
+#include "zend_interfaces.h"
#define DEBUG_OBJECT_HANDLERS 0
@@ -352,44 +353,49 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
zval *zend_std_read_dimension(zval *object, zval *offset TSRMLS_DC)
{
-#if 1
- zend_error(E_ERROR, "Cannot use object as array");
-#else
- zend_printf("Fetching from object: ");
- zend_print_zval(object, 0);
-
- zend_printf("\n the offset: ");
- zend_print_zval(offset, 0);
-
- zend_printf("\n");
-#endif
- return EG(uninitialized_zval_ptr);
+ zend_class_entry *ce = Z_OBJCE_P(object);
+ zval *retval;
+
+ if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
+ if (retval->refcount > 0) { /* Should always be the case */
+ retval->refcount--;
+ }
+ return retval;
+ } else {
+ zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
+ return 0;
+ }
}
static void zend_std_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
{
-#if 1
- zend_error(E_ERROR, "Cannot use object as array");
-#else
- zend_printf("Assigning to object: ");
- zend_print_zval(object, 0);
-
- zend_printf("\n with offset: ");
- zend_print_zval(offset, 0);
-
- zend_printf("\n the value: ");
- zend_print_zval(value, 0);
-
- zend_printf("\n");
-#endif
+ zend_class_entry *ce = Z_OBJCE_P(object);
+
+ if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+ zend_call_method_with_2_params(&object, ce, NULL, "offsetset", NULL, offset, value);
+ } else {
+ zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
+ }
}
static int zend_std_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC)
{
- zend_error(E_ERROR, "Cannot use object as array");
- return 0;
+ zend_class_entry *ce = Z_OBJCE_P(object);
+ zval *retval;
+ int result;
+
+ if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetexists", &retval, offset);
+ result = i_zend_is_true(retval);
+ zval_ptr_dtor(&retval);
+ return result;
+ } else {
+ zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
+ return 0;
+ }
}
@@ -463,7 +469,15 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
static void zend_std_unset_dimension(zval *object, zval *offset TSRMLS_DC)
{
- zend_error(E_ERROR, "Cannot use object as array");
+ zend_class_entry *ce = Z_OBJCE_P(object);
+ zval *retval;
+
+ if (instanceof_function_ex(ce, zend_ce_arrayaccess, 1 TSRMLS_CC)) {
+ zend_call_method_with_1_params(&object, ce, NULL, "offsetunset", &retval, offset);
+ zval_ptr_dtor(&retval);
+ } else {
+ zend_error(E_ERROR, "Cannot use object of type %s as array", ce->name);
+ }
}
View
@@ -1410,7 +1410,7 @@ ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSR
}
-ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC)
+ZEND_API zend_bool instanceof_function_ex(zend_class_entry *instance_ce, zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC)
{
zend_uint i;
@@ -1419,16 +1419,23 @@ ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class
return 1;
}
}
- while (instance_ce) {
- if (instance_ce == ce) {
- return 1;
+ if (!interfaces_only) {
+ while (instance_ce) {
+ if (instance_ce == ce) {
+ return 1;
+ }
+ instance_ce = instance_ce->parent;
}
- instance_ce = instance_ce->parent;
}
return 0;
}
+ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC)
+{
+ return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
+}
+
#define LOWER_CASE 1
#define UPPER_CASE 2
#define NUMERIC 3
View
@@ -59,6 +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 zend_bool instanceof_function_ex(zend_class_entry *instance_ce, zend_class_entry *ce, zend_bool interfaces_only 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)
Oops, something went wrong.

0 comments on commit 4dba05d

Please sign in to comment.