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:
@@ -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 {
|
||||
|
||||
@@ -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; \
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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") \
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user