]> granicus.if.org Git - php/commitdiff
Call offsetGet() when called with isset() on ArrayObject derivatives
authorTjerk Meesters <datibbaw@php.net>
Tue, 25 Mar 2014 10:15:18 +0000 (18:15 +0800)
committerTjerk Meesters <datibbaw@php.net>
Tue, 25 Mar 2014 10:15:18 +0000 (18:15 +0800)
ext/spl/spl_array.c
ext/spl/tests/bug66834.phpt [new file with mode: 0644]

index f41d0fb9cd9a23455e952ab3169c8bad049d3918..0611cfe38f63fbf6f8f3edce483992f22aa38481 100644 (file)
@@ -593,64 +593,80 @@ static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *o
 {
        spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
        long index;
-       zval *rv, **tmp;
+       zval *rv, *value = NULL, **tmp;
 
        if (check_inherited && intern->fptr_offset_has) {
-               SEPARATE_ARG_IF_REF(offset);
-               zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
-               zval_ptr_dtor(&offset);
+               zval *offset_tmp = offset;
+               SEPARATE_ARG_IF_REF(offset_tmp);
+               zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset_tmp);
+               zval_ptr_dtor(&offset_tmp);
+
                if (rv && zend_is_true(rv)) {
                        zval_ptr_dtor(&rv);
-                       return 1;
-               }
-               if (rv) {
-                       zval_ptr_dtor(&rv);
+                       if (check_empty == 2) {
+                               return 1;
+                       } else if (intern->fptr_offset_get) {
+                               value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R TSRMLS_CC);
+                       }
+               } else {
+                       if (rv) {
+                               zval_ptr_dtor(&rv);
+                       }
+                       return 0;
                }
-               return 0;
        }
 
-       switch(Z_TYPE_P(offset)) {
-               case IS_STRING:
-                       {
-                               HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+       if (!value) {
+               HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+
+               switch(Z_TYPE_P(offset)) {
+                       case IS_STRING: 
                                if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) {
-                                       switch (check_empty) {
-                                               case 0:
-                                                       return Z_TYPE_PP(tmp) != IS_NULL;
-                                               case 2:
-                                                       return 1;
-                                               default:
-                                                       return zend_is_true(*tmp);
+                                       if (check_empty == 2) {
+                                               return 1;
                                        }
+                               } else {
+                                       return 0;
                                }
-                       }
-                       return 0;
-               case IS_DOUBLE:
-               case IS_RESOURCE:
-               case IS_BOOL:
-               case IS_LONG:
-                       {
-                               HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
+                               break;
+                       case IS_DOUBLE:
+                       case IS_RESOURCE:
+                       case IS_BOOL: 
+                       case IS_LONG:
                                if (offset->type == IS_DOUBLE) {
                                        index = (long)Z_DVAL_P(offset);
                                } else {
                                        index = Z_LVAL_P(offset);
                                }
                                if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
-                                       switch (check_empty) {
-                                               case 0:
-                                                       return Z_TYPE_PP(tmp) != IS_NULL;
-                                               case 2:
-                                                       return 1;
-                                               default:
-                                                       return zend_is_true(*tmp);
+                                       if (check_empty == 2) {
+                                               return 1;
                                        }
+                               } else {
+                                       return 0;
                                }
+                               break;
+                       default:
+                               zend_error(E_WARNING, "Illegal offset type");
                                return 0;
-                       }
-               default:
-                       zend_error(E_WARNING, "Illegal offset type");
+               }
+
+               if (check_inherited && intern->fptr_offset_get) {
+                       value = spl_array_read_dimension_ex(1, object, offset, BP_VAR_R TSRMLS_CC);
+               } else {
+                       value = *tmp;
+               }
+       }
+
+       switch (check_empty) {
+               case 0:
+                       return Z_TYPE_P(value) != IS_NULL;
+               case 2:
+                       return 1;
+               case 1:
+                       return zend_is_true(value);
        }
+
        return 0;
 } /* }}} */
 
diff --git a/ext/spl/tests/bug66834.phpt b/ext/spl/tests/bug66834.phpt
new file mode 100644 (file)
index 0000000..6d944b2
--- /dev/null
@@ -0,0 +1,163 @@
+--TEST--
+SPL: Bug #66834
+--FILE--
+<?php
+
+// overrides both offsetExists and offsetGet
+class ArrayObjectBoth extends ArrayObject 
+{
+       public function offsetExists($offset) {
+               var_dump('Called: '.__METHOD__);
+               return parent::offsetExists($offset);
+       }
+
+       public function offsetGet($offset) {
+               var_dump('Called: '.__METHOD__);
+               return parent::offsetGet($offset);
+       }
+}
+
+// overrides only offsetExists
+class ArrayObjectExists extends ArrayObject 
+{
+       public function offsetExists($offset) {
+               var_dump('Called: '.__METHOD__);
+               return parent::offsetExists($offset);
+       }
+}
+
+// overrides only offsetGet
+class ArrayObjectGet extends ArrayObject 
+{
+       public function offsetGet($offset) {
+               var_dump('Called: '.__METHOD__);
+               return parent::offsetGet($offset);
+       }
+}
+
+// overrides only offsetGet and offsetSet
+class ArrayObjectGetSet extends ArrayObject
+{
+       public function offsetGet($offset)
+       {
+               return parent::offsetGet(str_rot13($offset));
+       }
+
+       public function offsetSet($offset, $value)
+       {
+               return parent::offsetSet(str_rot13($offset), $value);
+       }
+}
+
+$values = ['foo' => '', 'bar' => null, 'baz' => 42];
+
+echo "==== class with offsetExists() and offsetGet() ====\n";
+$object = new ArrayObjectBoth($values);
+var_dump($object->offsetExists('foo'), isset($object['foo']), empty($object['foo']));
+var_dump($object->offsetExists('bar'), isset($object['bar']), empty($object['bar']));
+var_dump($object->offsetexists('baz'), isset($object['baz']), empty($object['baz']));
+var_dump($object->offsetexists('qux'), isset($object['qux']), empty($object['qux']));
+
+echo "==== class with offsetExists() ====\n";
+$object = new ArrayObjectExists($values);
+var_dump($object->offsetExists('foo'), isset($object['foo']), empty($object['foo']));
+var_dump($object->offsetExists('bar'), isset($object['bar']), empty($object['bar']));
+var_dump($object->offsetexists('baz'), isset($object['baz']), empty($object['baz']));
+var_dump($object->offsetexists('qux'), isset($object['qux']), empty($object['qux']));
+
+echo "==== class with offsetGet() ====\n";
+$object = new ArrayObjectGet($values);
+var_dump($object->offsetExists('foo'), isset($object['foo']), empty($object['foo']));
+var_dump($object->offsetExists('bar'), isset($object['bar']), empty($object['bar']));
+var_dump($object->offsetexists('baz'), isset($object['baz']), empty($object['baz']));
+var_dump($object->offsetexists('qux'), isset($object['qux']), empty($object['qux']));
+
+echo "==== class with offsetGet() and offsetSet() ====\n";
+$object = new ArrayObjectGetSet;
+$object['foo'] = 42;
+var_dump($object->offsetExists('foo'), $object->offsetExists('sbb'), isset($object['foo']), isset($object['sbb']));
+
+?>
+--EXPECTF--
+==== class with offsetExists() and offsetGet() ====
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+bool(true)
+bool(true)
+bool(true)
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+bool(true)
+bool(false)
+bool(true)
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(34) "Called: ArrayObjectBoth::offsetGet"
+bool(true)
+bool(true)
+bool(false)
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+string(37) "Called: ArrayObjectBoth::offsetExists"
+bool(false)
+bool(false)
+bool(true)
+==== class with offsetExists() ====
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+bool(true)
+bool(true)
+bool(true)
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+bool(true)
+bool(false)
+bool(true)
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+bool(true)
+bool(true)
+bool(false)
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+string(39) "Called: ArrayObjectExists::offsetExists"
+bool(false)
+bool(false)
+bool(true)
+==== class with offsetGet() ====
+string(33) "Called: ArrayObjectGet::offsetGet"
+string(33) "Called: ArrayObjectGet::offsetGet"
+bool(true)
+bool(true)
+bool(true)
+string(33) "Called: ArrayObjectGet::offsetGet"
+string(33) "Called: ArrayObjectGet::offsetGet"
+bool(true)
+bool(false)
+bool(true)
+string(33) "Called: ArrayObjectGet::offsetGet"
+string(33) "Called: ArrayObjectGet::offsetGet"
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(true)
+==== class with offsetGet() and offsetSet() ====
+
+Notice: Undefined index: foo in %s on line %d
+bool(false)
+bool(true)
+bool(false)
+bool(false)