Browse Source

Call offsetGet() when called with isset() on ArrayObject derivatives

pull/801/head
Tjerk Meesters 12 years ago
parent
commit
5dee3c11fe
  1. 92
      ext/spl/spl_array.c
  2. 163
      ext/spl/tests/bug66834.phpt

92
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;
} /* }}} */

163
ext/spl/tests/bug66834.phpt

@ -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)
Loading…
Cancel
Save