]> granicus.if.org Git - php/commitdiff
Add new interface ArrayAccess to use objects as Arrays
authorMarcus Boerger <helly@php.net>
Mon, 24 Nov 2003 20:57:54 +0000 (20:57 +0000)
committerMarcus Boerger <helly@php.net>
Mon, 24 Nov 2003 20:57:54 +0000 (20:57 +0000)
Zend/zend_execute.c
Zend/zend_interfaces.c
Zend/zend_interfaces.h
Zend/zend_object_handlers.c
Zend/zend_operators.c
Zend/zend_operators.h
tests/classes/array_access_001.phpt [new file with mode: 0644]
tests/classes/array_access_002.phpt [new file with mode: 0644]
tests/classes/array_access_003.phpt [new file with mode: 0644]
tests/classes/array_access_004.phpt [new file with mode: 0644]

index 21d80531a1f671fff021ac7a2ef3d853b1edfd2a..be3ca78e22b4fb136cb92f7e78971ad74f550f1f 100644 (file)
@@ -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));
index 77a8deb6cd46665a91c12e5af9a19c16196ab499..52961b2caa0dc4aafa763272b93336a4e67026c1 100755 (executable)
@@ -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);
 }
 /* }}} */
 
index b7c671b9f2462a86308c6620611666a0ef2ea01d..2f881a5835335d519bb37909c832b171eec9a202 100755 (executable)
@@ -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);
 
index e0f3e4e145a99b1ec18e75f772a1b7bf2c46ac98..35c87eb22553f765485ef95de3ce18f44173f570 100644 (file)
@@ -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);
+       }
 }
 
 
index 6b581138e3a5f52320f1e82cbf933e98c1d6e1f4..8a6f78e6456b9df029f29889f732f1198a850cc5 100644 (file)
@@ -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
index bd2b39acdb1525947180026f2b06fcfedb15d536..db0f9560569a38220546c162171d96305e6566f9 100644 (file)
@@ -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)
diff --git a/tests/classes/array_access_001.phpt b/tests/classes/array_access_001.phpt
new file mode 100644 (file)
index 0000000..08b741e
--- /dev/null
@@ -0,0 +1,198 @@
+--TEST--
+ZE2 ArrayAccess
+--SKIPIF--
+<?php
+       if (!class_exists('ArrayAccess')) die('skip ArrayAccess not present');
+?>
+--FILE--
+<?php
+class Object implements ArrayAccess {
+
+       public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+       function offsetExists($index) {
+               echo __METHOD__ . "($index)\n";
+               return array_key_exists($index, $this->a);
+       }
+       function offsetGet($index) {
+               echo __METHOD__ . "($index)\n";
+               return $this->a[$index];
+       }
+       function offsetSet($index, $newval) {
+               echo __METHOD__ . "($index,$newval)\n";
+               return $this->a[$index] = $newval;
+       }
+       function offsetUnset($index) {
+               echo __METHOD__ . "($index)\n";
+               unset($this->a[$index]);
+       }
+}
+
+$obj = new Object;
+
+var_dump($obj->a);
+
+echo "===EMPTY===\n";
+var_dump(empty($obj[0]));
+var_dump(empty($obj[1]));
+var_dump(empty($obj[2]));
+var_dump(empty($obj['4th']));
+var_dump(empty($obj['5th']));
+var_dump(empty($obj[6]));
+
+echo "===isset===\n";
+var_dump(isset($obj[0]));
+var_dump(isset($obj[1]));
+var_dump(isset($obj[2]));
+var_dump(isset($obj['4th']));
+var_dump(isset($obj['5th']));
+var_dump(isset($obj[6]));
+
+echo "===offsetGet===\n";
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "===offsetSet===\n";
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+echo "===unset===\n";
+var_dump($obj->a);
+unset($obj[2]);
+unset($obj['4th']);
+unset($obj[7]);
+unset($obj['8th']);
+var_dump($obj->a);
+
+?>
+===DONE===
+--EXPECTF--
+array(4) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  int(1)
+  [2]=>
+  string(3) "3rd"
+  ["4th"]=>
+  int(4)
+}
+===EMPTY===
+object::offsetExists(0)
+bool(false)
+object::offsetExists(1)
+bool(false)
+object::offsetExists(2)
+bool(false)
+object::offsetExists(4th)
+bool(false)
+object::offsetExists(5th)
+bool(true)
+object::offsetExists(6)
+bool(true)
+===isset===
+object::offsetExists(0)
+bool(true)
+object::offsetExists(1)
+bool(true)
+object::offsetExists(2)
+bool(true)
+object::offsetExists(4th)
+bool(true)
+object::offsetExists(5th)
+bool(false)
+object::offsetExists(6)
+bool(false)
+===offsetGet===
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(1)
+int(1)
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetGet(4th)
+int(4)
+object::offsetGet(5th)
+
+Notice: Undefined index:  5th in %sarray_access_001.php on line %d
+NULL
+object::offsetGet(6)
+
+Notice: Undefined offset:  6 in %sarray_access_001.php on line %d
+NULL
+===offsetSet===
+WRITE 1
+object::offsetSet(1,Changed 1)
+object::offsetGet(1)
+string(9) "Changed 1"
+WRITE 2
+object::offsetSet(4th,Changed 4th)
+object::offsetGet(4th)
+string(11) "Changed 4th"
+WRITE 3
+object::offsetSet(5th,Added 5th)
+object::offsetGet(5th)
+string(9) "Added 5th"
+WRITE 4
+object::offsetSet(6,Added 6)
+object::offsetGet(6)
+string(7) "Added 6"
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetSet(6,changed 6)
+object::offsetGet(6)
+string(9) "changed 6"
+string(9) "changed 6"
+===unset===
+array(6) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  string(9) "Changed 1"
+  [2]=>
+  string(3) "3rd"
+  ["4th"]=>
+  string(11) "Changed 4th"
+  ["5th"]=>
+  string(9) "Added 5th"
+  [6]=>
+  string(9) "changed 6"
+}
+object::offsetUnset(2)
+object::offsetUnset(4th)
+object::offsetUnset(7)
+object::offsetUnset(8th)
+array(4) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  string(9) "Changed 1"
+  ["5th"]=>
+  string(9) "Added 5th"
+  [6]=>
+  string(9) "changed 6"
+}
+===DONE===
diff --git a/tests/classes/array_access_002.phpt b/tests/classes/array_access_002.phpt
new file mode 100644 (file)
index 0000000..cb4416d
--- /dev/null
@@ -0,0 +1,198 @@
+--TEST--
+ZE2 ArrayAccess::offsetSet without return
+--SKIPIF--
+<?php
+       if (!class_exists('ArrayAccess')) die('skip ArrayAccess not present');
+?>
+--FILE--
+<?php
+class Object implements ArrayAccess {
+
+       public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+       function offsetExists($index) {
+               echo __METHOD__ . "($index)\n";
+               return array_key_exists($index, $this->a);
+       }
+       function offsetGet($index) {
+               echo __METHOD__ . "($index)\n";
+               return $this->a[$index];
+       }
+       function offsetSet($index, $newval) {
+               echo __METHOD__ . "($index,$newval)\n";
+               /*return*/ $this->a[$index] = $newval;
+       }
+       function offsetUnset($index) {
+               echo __METHOD__ . "($index)\n";
+               unset($this->a[$index]);
+       }
+}
+
+$obj = new Object;
+
+var_dump($obj->a);
+
+echo "===EMPTY===\n";
+var_dump(empty($obj[0]));
+var_dump(empty($obj[1]));
+var_dump(empty($obj[2]));
+var_dump(empty($obj['4th']));
+var_dump(empty($obj['5th']));
+var_dump(empty($obj[6]));
+
+echo "===isset===\n";
+var_dump(isset($obj[0]));
+var_dump(isset($obj[1]));
+var_dump(isset($obj[2]));
+var_dump(isset($obj['4th']));
+var_dump(isset($obj['5th']));
+var_dump(isset($obj[6]));
+
+echo "===offsetGet===\n";
+var_dump($obj[0]);
+var_dump($obj[1]);
+var_dump($obj[2]);
+var_dump($obj['4th']);
+var_dump($obj['5th']);
+var_dump($obj[6]);
+
+echo "===offsetSet===\n";
+echo "WRITE 1\n";
+$obj[1] = 'Changed 1';
+var_dump($obj[1]);
+echo "WRITE 2\n";
+$obj['4th'] = 'Changed 4th';
+var_dump($obj['4th']);
+echo "WRITE 3\n";
+$obj['5th'] = 'Added 5th';
+var_dump($obj['5th']);
+echo "WRITE 4\n";
+$obj[6] = 'Added 6';
+var_dump($obj[6]);
+
+var_dump($obj[0]);
+var_dump($obj[2]);
+
+$x = $obj[6] = 'changed 6';
+var_dump($obj[6]);
+var_dump($x);
+
+echo "===unset===\n";
+var_dump($obj->a);
+unset($obj[2]);
+unset($obj['4th']);
+unset($obj[7]);
+unset($obj['8th']);
+var_dump($obj->a);
+
+?>
+===DONE===
+--EXPECTF--
+array(4) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  int(1)
+  [2]=>
+  string(3) "3rd"
+  ["4th"]=>
+  int(4)
+}
+===EMPTY===
+object::offsetExists(0)
+bool(false)
+object::offsetExists(1)
+bool(false)
+object::offsetExists(2)
+bool(false)
+object::offsetExists(4th)
+bool(false)
+object::offsetExists(5th)
+bool(true)
+object::offsetExists(6)
+bool(true)
+===isset===
+object::offsetExists(0)
+bool(true)
+object::offsetExists(1)
+bool(true)
+object::offsetExists(2)
+bool(true)
+object::offsetExists(4th)
+bool(true)
+object::offsetExists(5th)
+bool(false)
+object::offsetExists(6)
+bool(false)
+===offsetGet===
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(1)
+int(1)
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetGet(4th)
+int(4)
+object::offsetGet(5th)
+
+Notice: Undefined index:  5th in %sarray_access_002.php on line %d
+NULL
+object::offsetGet(6)
+
+Notice: Undefined offset:  6 in %sarray_access_002.php on line %d
+NULL
+===offsetSet===
+WRITE 1
+object::offsetSet(1,Changed 1)
+object::offsetGet(1)
+string(9) "Changed 1"
+WRITE 2
+object::offsetSet(4th,Changed 4th)
+object::offsetGet(4th)
+string(11) "Changed 4th"
+WRITE 3
+object::offsetSet(5th,Added 5th)
+object::offsetGet(5th)
+string(9) "Added 5th"
+WRITE 4
+object::offsetSet(6,Added 6)
+object::offsetGet(6)
+string(7) "Added 6"
+object::offsetGet(0)
+string(3) "1st"
+object::offsetGet(2)
+string(3) "3rd"
+object::offsetSet(6,changed 6)
+object::offsetGet(6)
+string(9) "changed 6"
+string(9) "changed 6"
+===unset===
+array(6) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  string(9) "Changed 1"
+  [2]=>
+  string(3) "3rd"
+  ["4th"]=>
+  string(11) "Changed 4th"
+  ["5th"]=>
+  string(9) "Added 5th"
+  [6]=>
+  string(9) "changed 6"
+}
+object::offsetUnset(2)
+object::offsetUnset(4th)
+object::offsetUnset(7)
+object::offsetUnset(8th)
+array(4) {
+  [0]=>
+  string(3) "1st"
+  [1]=>
+  string(9) "Changed 1"
+  ["5th"]=>
+  string(9) "Added 5th"
+  [6]=>
+  string(9) "changed 6"
+}
+===DONE===
diff --git a/tests/classes/array_access_003.phpt b/tests/classes/array_access_003.phpt
new file mode 100644 (file)
index 0000000..f19e23d
--- /dev/null
@@ -0,0 +1,59 @@
+--TEST--
+ZE2 ArrayAccess::offsetGet ambiguties
+--SKIPIF--
+<?php
+       if (!class_exists('ArrayAccess')) die('skip ArrayAccess not present');
+?>
+--FILE--
+<?php
+class Object implements ArrayAccess {
+
+       public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+       function offsetExists($index) {
+               echo __METHOD__ . "($index)\n";
+               return array_key_exists($index, $this->a);
+       }
+       function &offsetGet($index) {
+               echo __METHOD__ . "($index)\n";
+               switch($index) {
+               case 1:
+                       $a = 'foo';
+                       return $a . 'Bar';
+               case 2:
+                       static $a=1;
+                       return $a;
+               }
+               return $this->a[$index];
+       }
+       function offsetSet($index, $newval) {
+               echo __METHOD__ . "($index,$newval)\n";
+               if ($index==3) {
+                       $this->cnt = $newval;
+               }
+               return $this->a[$index] = $newval;
+       }
+       function offsetUnset($index) {
+               echo __METHOD__ . "($index)\n";
+               unset($this->a[$index]);
+       }
+}
+
+$obj = new Object;
+
+var_dump($obj[1]);
+var_dump($obj[2]);
+$obj[2]++;
+var_dump($obj[2]);
+
+?>
+===DONE===
+--EXPECTF--
+object::offsetGet(1)
+string(6) "fooBar"
+object::offsetGet(2)
+int(1)
+object::offsetGet(2)
+object::offsetGet(2)
+int(2)
+===DONE===
diff --git a/tests/classes/array_access_004.phpt b/tests/classes/array_access_004.phpt
new file mode 100644 (file)
index 0000000..8032d28
--- /dev/null
@@ -0,0 +1,58 @@
+--TEST--
+ZE2 ArrayAccess::offsetGet ambiguties
+--SKIPIF--
+<?php
+       if (!class_exists('ArrayAccess')) die('skip ArrayAccess not present');
+?>
+--FILE--
+<?php
+class Object implements ArrayAccess {
+
+       public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
+
+       function offsetExists($index) {
+               echo __METHOD__ . "($index)\n";
+               return array_key_exists($index, $this->a);
+       }
+       function offsetGet($index) {
+               echo __METHOD__ . "($index)\n";
+               switch($index) {
+               case 1:
+                       $a = 'foo';
+                       return $a . 'Bar';
+               case 2:
+                       static $a=1;
+                       return $a;
+               }
+               return $this->a[$index];
+       }
+       function offsetSet($index, $newval) {
+               echo __METHOD__ . "($index,$newval)\n";
+               if ($index==3) {
+                       $this->cnt = $newval;
+               }
+               return $this->a[$index] = $newval;
+       }
+       function offsetUnset($index) {
+               echo __METHOD__ . "($index)\n";
+               unset($this->a[$index]);
+       }
+}
+
+$obj = new Object;
+
+var_dump($obj[1]);
+var_dump($obj[2]);
+$obj[2]++;
+var_dump($obj[2]);
+
+?>
+===DONE===
+--EXPECTF--
+object::offsetGet(1)
+string(6) "fooBar"
+object::offsetGet(2)
+int(1)
+object::offsetGet(2)
+
+Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %sarray_access_004.php on line %d