1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Cache method overrides of ArrayAccess in zend_class_entry

Previously, code such as subclasses of SplFixedArray would check for method
overrides when instantiating the objects.

This optimization was mentioned as a followup to GH-6552
This commit is contained in:
Tyson Andre
2021-12-01 18:43:37 -05:00
parent 8ba1267744
commit 024d5f4b63
13 changed files with 112 additions and 98 deletions

View File

@@ -183,6 +183,8 @@ struct _zend_class_entry {
/* allocated only if class implements Iterator or IteratorAggregate interface */
zend_class_iterator_funcs *iterator_funcs_ptr;
/* allocated only if class implements ArrayAccess interface */
zend_class_arrayaccess_funcs *arrayaccess_funcs_ptr;
/* handlers */
union {

View File

@@ -292,6 +292,7 @@ typedef struct _zend_fcall_info_cache {
class_container.interfaces = NULL; \
class_container.get_iterator = NULL; \
class_container.iterator_funcs_ptr = NULL; \
class_container.arrayaccess_funcs_ptr = NULL; \
class_container.info.internal.module = NULL; \
class_container.info.internal.builtin_functions = functions; \
}

View File

@@ -1802,6 +1802,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_hand
ce->create_object = NULL;
ce->get_iterator = NULL;
ce->iterator_funcs_ptr = NULL;
ce->arrayaccess_funcs_ptr = NULL;
ce->get_static_method = NULL;
ce->parent = NULL;
ce->parent_name = NULL;

View File

@@ -359,6 +359,28 @@ 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)
{
ZEND_ASSERT(!class_type->arrayaccess_funcs_ptr && "ArrayAccess funcs already set?");
zend_class_arrayaccess_funcs *funcs_ptr = class_type->type == ZEND_INTERNAL_CLASS
? pemalloc(sizeof(zend_class_arrayaccess_funcs), 1)
: zend_arena_alloc(&CG(arena), sizeof(zend_class_arrayaccess_funcs));
class_type->arrayaccess_funcs_ptr = funcs_ptr;
funcs_ptr->zf_offsetget = zend_hash_str_find_ptr(
&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr(
&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
funcs_ptr->zf_offsetset = zend_hash_str_find_ptr(
&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr(
&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
return SUCCESS;
}
/* }}} */
/* {{{ zend_user_serialize */
ZEND_API int zend_user_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
{
@@ -616,6 +638,7 @@ ZEND_API void zend_register_interfaces(void)
zend_ce_serializable->interface_gets_implemented = zend_implement_serializable;
zend_ce_arrayaccess = register_class_ArrayAccess();
zend_ce_arrayaccess->interface_gets_implemented = zend_implement_arrayaccess;
zend_ce_countable = register_class_Countable();

View File

@@ -72,6 +72,13 @@ typedef struct _zend_class_iterator_funcs {
zend_function *zf_rewind;
} zend_class_iterator_funcs;
typedef struct _zend_class_arrayaccess_funcs {
zend_function *zf_offsetget;
zend_function *zf_offsetexists;
zend_function *zf_offsetset;
zend_function *zf_offsetunset;
} zend_class_arrayaccess_funcs;
BEGIN_EXTERN_C()
/* given a zval, returns stuff that can be used to iterate it. */
ZEND_API zend_object_iterator* zend_iterator_unwrap(zval *array_ptr);

View File

@@ -908,7 +908,9 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty
zend_class_entry *ce = object->ce;
zval tmp_offset;
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
/* arrayaccess_funcs_ptr is set if (and only if) the class implements zend_ce_arrayaccess */
zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr;
if (EXPECTED(funcs)) {
if (offset == NULL) {
/* [] construct */
ZVAL_NULL(&tmp_offset);
@@ -918,9 +920,7 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty
GC_ADDREF(object);
if (type == BP_VAR_IS) {
zend_function *offsetexists =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETEXISTS));
zend_call_known_instance_method_with_1_params(offsetexists, object, rv, &tmp_offset);
zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, rv, &tmp_offset);
if (UNEXPECTED(Z_ISUNDEF_P(rv))) {
OBJ_RELEASE(object);
zval_ptr_dtor(&tmp_offset);
@@ -935,9 +935,7 @@ ZEND_API zval *zend_std_read_dimension(zend_object *object, zval *offset, int ty
zval_ptr_dtor(rv);
}
zend_function *offsetget =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETGET));
zend_call_known_instance_method_with_1_params(offsetget, object, rv, &tmp_offset);
zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, rv, &tmp_offset);
OBJ_RELEASE(object);
zval_ptr_dtor(&tmp_offset);
@@ -961,16 +959,15 @@ ZEND_API void zend_std_write_dimension(zend_object *object, zval *offset, zval *
zend_class_entry *ce = object->ce;
zval tmp_offset;
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr;
if (EXPECTED(funcs)) {
if (!offset) {
ZVAL_NULL(&tmp_offset);
} else {
ZVAL_COPY_DEREF(&tmp_offset, offset);
}
GC_ADDREF(object);
zend_function *offsetset =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETSET));
zend_call_known_instance_method_with_2_params(offsetset, object, NULL, &tmp_offset, value);
zend_call_known_instance_method_with_2_params(funcs->zf_offsetset, object, NULL, &tmp_offset, value);
OBJ_RELEASE(object);
zval_ptr_dtor(&tmp_offset);
} else {
@@ -985,18 +982,15 @@ ZEND_API int zend_std_has_dimension(zend_object *object, zval *offset, int check
zval retval, tmp_offset;
int result;
if (EXPECTED(zend_class_implements_interface(ce, zend_ce_arrayaccess) != 0)) {
zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr;
if (EXPECTED(funcs)) {
ZVAL_COPY_DEREF(&tmp_offset, offset);
GC_ADDREF(object);
zend_function *offsetexists =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETEXISTS));
zend_call_known_instance_method_with_1_params(offsetexists, object, &retval, &tmp_offset);
zend_call_known_instance_method_with_1_params(funcs->zf_offsetexists, object, &retval, &tmp_offset);
result = i_zend_is_true(&retval);
zval_ptr_dtor(&retval);
if (check_empty && result && EXPECTED(!EG(exception))) {
zend_function *offsetget =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETGET));
zend_call_known_instance_method_with_1_params(offsetget, object, &retval, &tmp_offset);
zend_call_known_instance_method_with_1_params(funcs->zf_offsetget, object, &retval, &tmp_offset);
result = i_zend_is_true(&retval);
zval_ptr_dtor(&retval);
}
@@ -1170,12 +1164,11 @@ ZEND_API void zend_std_unset_dimension(zend_object *object, zval *offset) /* {{{
zend_class_entry *ce = object->ce;
zval tmp_offset;
if (zend_class_implements_interface(ce, zend_ce_arrayaccess)) {
zend_class_arrayaccess_funcs *funcs = ce->arrayaccess_funcs_ptr;
if (EXPECTED(funcs)) {
ZVAL_COPY_DEREF(&tmp_offset, offset);
GC_ADDREF(object);
zend_function *offsetunset =
zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_OFFSETUNSET));
zend_call_known_instance_method_with_1_params(offsetunset, object, NULL, &tmp_offset);
zend_call_known_instance_method_with_1_params(funcs->zf_offsetunset, object, NULL, &tmp_offset);
OBJ_RELEASE(object);
zval_ptr_dtor(&tmp_offset);
} else {

View File

@@ -469,6 +469,9 @@ ZEND_API void destroy_zend_class(zval *zv)
if (ce->iterator_funcs_ptr) {
free(ce->iterator_funcs_ptr);
}
if (ce->arrayaccess_funcs_ptr) {
free(ce->arrayaccess_funcs_ptr);
}
if (ce->num_interfaces > 0) {
free(ce->interfaces);
}

View File

@@ -571,10 +571,6 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_AUTOGLOBAL_SERVER, "_SERVER") \
_(ZEND_STR_AUTOGLOBAL_ENV, "_ENV") \
_(ZEND_STR_AUTOGLOBAL_REQUEST, "_REQUEST") \
_(ZEND_STR_OFFSETGET, "offsetget") \
_(ZEND_STR_OFFSETSET, "offsetset") \
_(ZEND_STR_OFFSETEXISTS, "offsetexists") \
_(ZEND_STR_OFFSETUNSET, "offsetunset") \
_(ZEND_STR_COUNT, "count") \

View File

@@ -880,6 +880,14 @@ static void zend_file_cache_serialize_class(zval *zv,
SERIALIZE_PTR(ce->iterator_funcs_ptr);
}
if (ce->arrayaccess_funcs_ptr) {
SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget);
SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists);
SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset);
SERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset);
SERIALIZE_PTR(ce->arrayaccess_funcs_ptr);
}
ZEND_MAP_PTR_INIT(ce->static_members_table, NULL);
ZEND_MAP_PTR_INIT(ce->mutable_data, NULL);
}
@@ -1670,6 +1678,13 @@ static void zend_file_cache_unserialize_class(zval *zv,
UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_current);
UNSERIALIZE_PTR(ce->iterator_funcs_ptr->zf_next);
}
if (ce->arrayaccess_funcs_ptr) {
UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr);
UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetget);
UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetexists);
UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetset);
UNSERIALIZE_PTR(ce->arrayaccess_funcs_ptr->zf_offsetunset);
}
if (!(script->corrupted)) {
ce->ce_flags |= ZEND_ACC_IMMUTABLE;

View File

@@ -985,6 +985,9 @@ zend_class_entry *zend_persist_class_entry(zend_class_entry *orig_ce)
if (ce->iterator_funcs_ptr) {
ce->iterator_funcs_ptr = zend_shared_memdup(ce->iterator_funcs_ptr, sizeof(zend_class_iterator_funcs));
}
if (ce->arrayaccess_funcs_ptr) {
ce->arrayaccess_funcs_ptr = zend_shared_memdup(ce->arrayaccess_funcs_ptr, sizeof(zend_class_arrayaccess_funcs));
}
if (ce->ce_flags & ZEND_ACC_CACHED) {
return ce;
@@ -1135,6 +1138,14 @@ void zend_update_parent_ce(zend_class_entry *ce)
ce->iterator_funcs_ptr->zf_next = zend_hash_str_find_ptr(&ce->function_table, "next", sizeof("next") - 1);
}
}
if (ce->arrayaccess_funcs_ptr) {
ZEND_ASSERT(zend_class_implements_interface(ce, zend_ce_arrayaccess));
ce->arrayaccess_funcs_ptr->zf_offsetget = zend_hash_str_find_ptr(&ce->function_table, "offsetget", sizeof("offsetget") - 1);
ce->arrayaccess_funcs_ptr->zf_offsetexists = zend_hash_str_find_ptr(&ce->function_table, "offsetexists", sizeof("offsetexists") - 1);
ce->arrayaccess_funcs_ptr->zf_offsetset = zend_hash_str_find_ptr(&ce->function_table, "offsetset", sizeof("offsetset") - 1);
ce->arrayaccess_funcs_ptr->zf_offsetunset = zend_hash_str_find_ptr(&ce->function_table, "offsetunset", sizeof("offsetunset") - 1);
}
}
/* update methods */

View File

@@ -470,6 +470,9 @@ void zend_persist_class_entry_calc(zend_class_entry *ce)
if (ce->iterator_funcs_ptr) {
ADD_SIZE(sizeof(zend_class_iterator_funcs));
}
if (ce->arrayaccess_funcs_ptr) {
ADD_SIZE(sizeof(zend_class_arrayaccess_funcs));
}
if (ce->ce_flags & ZEND_ACC_CACHED) {
return;

View File

@@ -40,23 +40,19 @@ PHPAPI zend_class_entry *spl_ce_SplFixedArray;
ZEND_GET_MODULE(spl_fixedarray)
#endif
/* Check if the object is an instance of a subclass of SplFixedArray that overrides method's implementation.
* Expect subclassing SplFixedArray to be rare and check that first. */
#define HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, method) UNEXPECTED((object)->ce != spl_ce_SplFixedArray && (object)->ce->arrayaccess_funcs_ptr->method->common.scope != spl_ce_SplFixedArray)
typedef struct _spl_fixedarray {
zend_long size;
/* It is possible to resize this, so this can't be combined with the object */
zval *elements;
} spl_fixedarray;
typedef struct _spl_fixedarray_methods {
zend_function *fptr_offset_get;
zend_function *fptr_offset_set;
zend_function *fptr_offset_has;
zend_function *fptr_offset_del;
zend_function *fptr_count;
} spl_fixedarray_methods;
typedef struct _spl_fixedarray_object {
spl_fixedarray array;
spl_fixedarray_methods *methods;
zend_function *fptr_count;
zend_object std;
} spl_fixedarray_object;
@@ -233,9 +229,6 @@ static void spl_fixedarray_object_free_storage(zend_object *object)
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
spl_fixedarray_dtor(&intern->array);
zend_object_std_dtor(&intern->std);
if (intern->methods) {
efree(intern->methods);
}
}
static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, zend_object *orig, bool clone_orig)
@@ -267,34 +260,11 @@ static zend_object *spl_fixedarray_object_new_ex(zend_class_entry *class_type, z
ZEND_ASSERT(parent);
if (UNEXPECTED(inherited)) {
spl_fixedarray_methods methods;
methods.fptr_offset_get = zend_hash_str_find_ptr(&class_type->function_table, "offsetget", sizeof("offsetget") - 1);
if (methods.fptr_offset_get->common.scope == parent) {
methods.fptr_offset_get = NULL;
}
methods.fptr_offset_set = zend_hash_str_find_ptr(&class_type->function_table, "offsetset", sizeof("offsetset") - 1);
if (methods.fptr_offset_set->common.scope == parent) {
methods.fptr_offset_set = NULL;
}
methods.fptr_offset_has = zend_hash_str_find_ptr(&class_type->function_table, "offsetexists", sizeof("offsetexists") - 1);
if (methods.fptr_offset_has->common.scope == parent) {
methods.fptr_offset_has = NULL;
}
methods.fptr_offset_del = zend_hash_str_find_ptr(&class_type->function_table, "offsetunset", sizeof("offsetunset") - 1);
if (methods.fptr_offset_del->common.scope == parent) {
methods.fptr_offset_del = NULL;
}
methods.fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
if (methods.fptr_count->common.scope == parent) {
methods.fptr_count = NULL;
}
/* Assume that most of the time in performance-sensitive code, SplFixedArray won't be subclassed with overrides for these ArrayAccess methods. */
/* Save 32 bytes per object on 64-bit systems by combining the 5 null pointers into 1 null pointer */
/* (This is already looking up 5 functions when any subclass of SplFixedArray is instantiated, which is inefficient) */
if (methods.fptr_offset_get || methods.fptr_offset_set || methods.fptr_offset_del || methods.fptr_offset_has || methods.fptr_count) {
intern->methods = emalloc(sizeof(spl_fixedarray_methods));
*intern->methods = methods;
zend_function *fptr_count = zend_hash_str_find_ptr(&class_type->function_table, "count", sizeof("count") - 1);
if (fptr_count->common.scope == parent) {
fptr_count = NULL;
}
intern->fptr_count = fptr_count;
}
return &intern->std;
@@ -374,27 +344,24 @@ static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset
static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *offset, int type, zval *rv)
{
spl_fixedarray_object *intern;
intern = spl_fixed_array_from_obj(object);
if (type == BP_VAR_IS && !spl_fixedarray_object_has_dimension(object, offset, 0)) {
return &EG(uninitialized_zval);
}
if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_get)) {
if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetget)) {
zval tmp;
if (!offset) {
ZVAL_NULL(&tmp);
offset = &tmp;
}
zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_get, "offsetGet", rv, offset);
zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetget, object, rv, offset);
if (!Z_ISUNDEF_P(rv)) {
return rv;
}
return &EG(uninitialized_zval);
}
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
return spl_fixedarray_object_read_dimension_helper(intern, offset);
}
@@ -429,20 +396,18 @@ static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *
static void spl_fixedarray_object_write_dimension(zend_object *object, zval *offset, zval *value)
{
spl_fixedarray_object *intern;
zval tmp;
if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetset)) {
zval tmp;
intern = spl_fixed_array_from_obj(object);
if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_set)) {
if (!offset) {
ZVAL_NULL(&tmp);
offset = &tmp;
}
zend_call_method_with_2_params(object, intern->std.ce, &intern->methods->fptr_offset_set, "offsetSet", NULL, offset, value);
zend_call_known_instance_method_with_2_params(object->ce->arrayaccess_funcs_ptr->zf_offsetset, object, NULL, offset, value);
return;
}
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
spl_fixedarray_object_write_dimension_helper(intern, offset, value);
}
@@ -467,15 +432,12 @@ static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *
static void spl_fixedarray_object_unset_dimension(zend_object *object, zval *offset)
{
spl_fixedarray_object *intern;
intern = spl_fixed_array_from_obj(object);
if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_del)) {
zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_del, "offsetUnset", NULL, offset);
if (UNEXPECTED(HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetunset))) {
zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetunset, object, NULL, offset);
return;
}
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
spl_fixedarray_object_unset_dimension_helper(intern, offset);
}
@@ -501,20 +463,17 @@ static bool spl_fixedarray_object_has_dimension_helper(spl_fixedarray_object *in
static int spl_fixedarray_object_has_dimension(zend_object *object, zval *offset, int check_empty)
{
spl_fixedarray_object *intern;
intern = spl_fixed_array_from_obj(object);
if (UNEXPECTED(intern->methods && intern->methods->fptr_offset_has)) {
if (HAS_FIXEDARRAY_ARRAYACCESS_OVERRIDE(object, zf_offsetexists)) {
zval rv;
bool result;
zend_call_method_with_1_params(object, intern->std.ce, &intern->methods->fptr_offset_has, "offsetExists", &rv, offset);
result = zend_is_true(&rv);
zend_call_known_instance_method_with_1_params(object->ce->arrayaccess_funcs_ptr->zf_offsetexists, object, &rv, offset);
bool result = zend_is_true(&rv);
zval_ptr_dtor(&rv);
return result;
}
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
return spl_fixedarray_object_has_dimension_helper(intern, offset, check_empty);
}
@@ -523,9 +482,9 @@ static int spl_fixedarray_object_count_elements(zend_object *object, zend_long *
spl_fixedarray_object *intern;
intern = spl_fixed_array_from_obj(object);
if (UNEXPECTED(intern->methods && intern->methods->fptr_count)) {
if (UNEXPECTED(intern->fptr_count)) {
zval rv;
zend_call_method_with_0_params(object, intern->std.ce, &intern->methods->fptr_count, "count", &rv);
zend_call_known_instance_method_with_0_params(intern->fptr_count, object, &rv);
if (!Z_ISUNDEF(rv)) {
*count = zval_get_long(&rv);
zval_ptr_dtor(&rv);

View File

@@ -249,7 +249,7 @@ void spl_object_storage_addall(spl_SplObjectStorage *intern, spl_SplObjectStorag
} /* }}} */
#define SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zstr_method) \
(((zend_function *)zend_hash_find_ptr(&(class_type)->function_table, ZSTR_KNOWN(zstr_method)))->common.scope != spl_ce_SplObjectStorage)
(class_type->arrayaccess_funcs_ptr && class_type->arrayaccess_funcs_ptr->zstr_method)
static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend_object *orig) /* {{{ */
{
@@ -277,18 +277,18 @@ static zend_object *spl_object_storage_new_ex(zend_class_entry *class_type, zend
intern->fptr_get_hash = get_hash;
}
if (intern->fptr_get_hash != NULL ||
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETGET) ||
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETEXISTS)) {
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetget) ||
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetexists)) {
intern->flags |= SOS_OVERRIDDEN_READ_DIMENSION;
}
if (intern->fptr_get_hash != NULL ||
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETSET)) {
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetset)) {
intern->flags |= SOS_OVERRIDDEN_WRITE_DIMENSION;
}
if (intern->fptr_get_hash != NULL ||
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, ZEND_STR_OFFSETUNSET)) {
SPL_OBJECT_STORAGE_CLASS_HAS_OVERRIDE(class_type, zf_offsetunset)) {
intern->flags |= SOS_OVERRIDDEN_UNSET_DIMENSION;
}
}