From 5dee3c11fe4cb38e77642280923ece1b1eb14916 Mon Sep 17 00:00:00 2001 From: Tjerk Meesters Date: Tue, 25 Mar 2014 18:15:18 +0800 Subject: [PATCH] Call offsetGet() when called with isset() on ArrayObject derivatives --- ext/spl/spl_array.c | 92 +++++++++++--------- ext/spl/tests/bug66834.phpt | 163 ++++++++++++++++++++++++++++++++++++ 2 files changed, 217 insertions(+), 38 deletions(-) create mode 100644 ext/spl/tests/bug66834.phpt diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index f41d0fb9cd..0611cfe38f 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -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 index 0000000000..6d944b274a --- /dev/null +++ b/ext/spl/tests/bug66834.phpt @@ -0,0 +1,163 @@ +--TEST-- +SPL: Bug #66834 +--FILE-- + '', '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) -- 2.40.0