diff options
Diffstat (limited to 'ext/spl/spl_array.c')
-rwxr-xr-x | ext/spl/spl_array.c | 402 |
1 files changed, 74 insertions, 328 deletions
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 95132cb6c2..6df776ac6c 100755 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -23,317 +23,74 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "zend_compile.h" +#include "zend_interfaces.h" #include "php_spl.h" #include "spl_functions.h" #include "spl_engine.h" #include "spl_array.h" -#define DELETE_ZVAL(z) \ - if ((z)->refcount < 2) { \ - zval_dtor(z); \ - FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \ - } - -#define DELETE_RET_ZVAL(z) \ - if ((z)->refcount < 3) { \ - zval_dtor(z); \ - FREE_ZVAL(z); /* maybe safe_free_zval_ptr is needed for the uninitialised things */ \ - } - -#define AI_PTR_2_PTR_PTR(ai) \ - (ai).ptr_ptr = &((ai).ptr) - -/* {{{ spl_fetch_dimension_address */ -int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - obj = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - return 1; - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_READ) { - zval **retval = &(T(result->u.var).var.ptr); - zval *dim = spl_get_zval_ptr(op2, Ts, &EG(free_op2) TSRMLS_CC); - zval *exists; - - spl_call_method_1(obj, obj_ce, NULL, "exists", sizeof("exists")-1, &exists, dim); - if (!i_zend_is_true(exists)) { - if (type == BP_VAR_R || type == BP_VAR_RW) { - SEPARATE_ZVAL(&dim); - convert_to_string_ex(&dim); - zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(dim)); - DELETE_ZVAL(dim); - } - if (type == BP_VAR_R || type == BP_VAR_IS) { - DELETE_RET_ZVAL(exists); - *retval = &EG(error_zval); - (*retval)->refcount++; - FREE_OP(Ts, op2, EG(free_op2)); - SELECTIVE_PZVAL_LOCK(*retval, result); - return 0; - } - } - DELETE_RET_ZVAL(exists); - if (type == BP_VAR_R || type == BP_VAR_IS) { - spl_call_method_1(obj, obj_ce, NULL, "get", sizeof("get")-1, retval, dim); - } - FREE_OP(Ts, op2, EG(free_op2)); - return 0; - } - return 1; -} -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_R) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC)) - { - if (EX(opline)->extended_value == ZEND_FETCH_ADD_LOCK) { - spl_pzval_lock_func(*EX_T(EX(opline)->op1.u.var).var.ptr_ptr); - } - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - AI_PTR_2_PTR_PTR(EX_T(EX(opline)->result.u.var).var); - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_R); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_W) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC)) - { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_W); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW) */ -#ifdef SPL_ARRAY_READ -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW) -{ - if (!spl_fetch_dimension_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_RW TSRMLS_CC)) - { - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_FETCH_DIM_RW); -} -#endif -/* }}} */ - -static inline zval **spl_get_obj_zval_ptr_ptr(znode *op, temp_variable *Ts, int type TSRMLS_DC) -{ - if (op->op_type == IS_UNUSED) { - if (EG(This)) { - /* this should actually never be modified, _ptr_ptr is modified only when - the object is empty */ - return &EG(This); - } else { - zend_error(E_ERROR, "Using $this when not in object context"); - } - } - return spl_get_zval_ptr_ptr(op, Ts TSRMLS_CC); -} - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM) */ -#ifdef SPL_ARRAY_WRITE -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM); - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_ACCESS) { - znode *op2 = &EX(opline)->op2; - zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R); - zval *free_value; - zend_op *value_op = EX(opline)+1; - zval *value = spl_get_zval_ptr(&value_op->op1, EX(Ts), &free_value, BP_VAR_R); - zval tmp; - zval *retval; - - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - /* here we are sure we are dealing with an object */ - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *index; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - index = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(index); - break; - } - - /* separate our value if necessary */ - if (value_op->op1.op_type == IS_TMP_VAR) { - zval *orig_value = value; - - ALLOC_ZVAL(value); - *value = *orig_value; - value->is_ref = 0; - value->refcount = 0; - } - - spl_call_method_2(obj, obj_ce, NULL, "set", sizeof("set")-1, &retval, index, value); - - if (index == &tmp) { - zval_dtor(index); - } - - FREE_OP(Ts, op2, EG(free_op2)); - if (&EX(opline)->result) { - if (retval->refcount < 2) { - zend_error(E_WARNING, "Method %s::set() did not return a value, using input value", obj_ce->name); - EX_T(EX(opline)->result.u.var).var.ptr = value; - SELECTIVE_PZVAL_LOCK(value, &EX(opline)->result); - DELETE_RET_ZVAL(retval); - } else { - SELECTIVE_PZVAL_LOCK(retval, &EX(opline)->result); - EX_T(EX(opline)->result.u.var).var.ptr = retval; - retval->refcount--; - } - EX_T(EX(opline)->result.u.var).var.ptr_ptr = NULL; - } else { - DELETE_RET_ZVAL(retval); - } - - EX(opline)++; - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM); -} -#endif -/* }}} */ - -/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ) */ -#ifdef SPL_ARRAY_WRITE -ZEND_EXECUTE_HOOK_FUNCTION(ZEND_UNSET_DIM_OBJ) -{ - zval **obj; - zend_class_entry *obj_ce; - spl_is_a is_a; - - if (EX(opline)->extended_value != ZEND_UNSET_DIM) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); - } - - obj = spl_get_obj_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), 0 TSRMLS_CC); - - if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) { - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); - } - - is_a = spl_implements(obj_ce); - - if (is_a & SPL_IS_A_ARRAY_ACCESS) { - znode *op2 = &EX(opline)->op2; - zval *index = spl_get_zval_ptr(op2, EX(Ts), &EG(free_op2), BP_VAR_R); - zval tmp; - zval *retval; - - spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC); - - /* here we are sure we are dealing with an object */ - switch (op2->op_type) { - case IS_CONST: - /* already a constant string */ - break; - case IS_VAR: - tmp = *index; - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - index = &tmp; - break; - case IS_TMP_VAR: - convert_to_string(index); - break; - } - - spl_call_method_1(obj, obj_ce, NULL, "del", sizeof("del")-1, &retval, index); +static +ZEND_BEGIN_ARG_INFO(arginfo_one_param, 0) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO(); - if (index == &tmp) { - zval_dtor(index); - } +static +ZEND_BEGIN_ARG_INFO(arginfo_two_params, 0) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, value) +ZEND_END_ARG_INFO(); - FREE_OP(Ts, op2, EG(free_op2)); - DELETE_RET_ZVAL(retval); +function_entry spl_funcs_ArrayRead[] = { + SPL_ABSTRACT_ME(ArrayRead, get, arginfo_one_param) + SPL_ABSTRACT_ME(ArrayRead, exists, arginfo_one_param) + {NULL, NULL, NULL} +}; - NEXT_OPCODE(); - } - ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_UNSET_DIM_OBJ); -} -#endif -/* }}} */ +function_entry spl_funcs_ArrayAccess[] = { + SPL_ABSTRACT_ME(ArrayAccess, set, arginfo_two_params) + SPL_ABSTRACT_ME(ArrayAccess, del, arginfo_one_param) + {NULL, NULL, NULL} +}; -SPL_CLASS_FUNCTION(array, __construct); -SPL_CLASS_FUNCTION(array, newIterator); -SPL_CLASS_FUNCTION(array, rewind); -SPL_CLASS_FUNCTION(array, current); -SPL_CLASS_FUNCTION(array, key); -SPL_CLASS_FUNCTION(array, next); -SPL_CLASS_FUNCTION(array, hasMore); +SPL_METHOD(Array, __construct); +SPL_METHOD(Array, getIterator); +SPL_METHOD(Array, rewind); +SPL_METHOD(Array, current); +SPL_METHOD(Array, key); +SPL_METHOD(Array, next); +SPL_METHOD(Array, hasMore); static ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO(); -static zend_function_entry spl_array_class_functions[] = { - SPL_CLASS_FE(array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, newIterator, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry spl_funcs_ArrayClass[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC) + SPL_ME(Array, getIterator, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; -static zend_function_entry spl_array_it_class_functions[] = { - SPL_CLASS_FE(array, __construct, arginfo_array___construct, ZEND_ACC_PRIVATE) - SPL_CLASS_FE(array, rewind, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, current, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, key, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, next, NULL, ZEND_ACC_PUBLIC) - SPL_CLASS_FE(array, hasMore, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry spl_funcs_ArrayIterator[] = { + SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PRIVATE) + SPL_ME(Array, rewind, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, current, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, key, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, next, NULL, ZEND_ACC_PUBLIC) + SPL_ME(Array, hasMore, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; -static zend_object_handlers spl_array_handlers; -static zend_class_entry * spl_ce_array; +zend_class_entry * spl_ce_ArrayRead; +zend_class_entry * spl_ce_ArrayAccess; -static zend_object_handlers spl_array_it_handlers; -static zend_class_entry * spl_ce_array_it; +zend_object_handlers spl_handler_ArrayClass; +zend_class_entry * spl_ce_ArrayClass; + +zend_object_handlers spl_handler_ArrayIterator; +zend_class_entry * spl_ce_ArrayIterator; typedef struct _spl_array_object { zend_object std; @@ -384,10 +141,10 @@ static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, s zend_hash_internal_pointer_reset_ex(HASH_OF(intern->array), &intern->pos); retval.handle = zend_objects_store_put(intern, spl_array_object_dtor, NULL TSRMLS_CC); - if (class_type == spl_ce_array_it) { - retval.handlers = &spl_array_it_handlers; + if (class_type == spl_ce_ArrayIterator) { + retval.handlers = &spl_handler_ArrayIterator; } else { - retval.handlers = &spl_array_handlers; + retval.handlers = &spl_handler_ArrayClass; } return retval; } @@ -420,20 +177,6 @@ static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC) } /* }}} */ -/* {{{ spl_array_get_ce */ -static zend_class_entry *spl_array_get_ce(zval *object TSRMLS_DC) -{ - return spl_ce_array; -} -/* }}} */ - -/* {{{ spl_array_it_get_ce */ -static zend_class_entry *spl_array_it_get_ce(zval *object TSRMLS_DC) -{ - return spl_ce_array_it; -} -/* }}} */ - /* {{{ spl_array_read_dimension */ static zval *spl_array_read_dimension(zval *object, zval *offset TSRMLS_DC) { @@ -544,20 +287,23 @@ static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ PHP_MINIT_FUNCTION(spl_array) */ PHP_MINIT_FUNCTION(spl_array) { - REGISTER_SPL_STD_CLASS_EX(array, spl_array_object_new, spl_array_class_functions); - REGISTER_SPL_IMPLEMENT(array, iterator); - memcpy(&spl_array_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - spl_array_handlers.clone_obj = spl_array_object_clone; - spl_array_handlers.get_class_entry = spl_array_get_ce; - spl_array_handlers.read_dimension = spl_array_read_dimension; - spl_array_handlers.write_dimension = spl_array_write_dimension; - spl_array_handlers.unset_dimension = spl_array_unset_dimension; - spl_array_handlers.get_properties = spl_array_get_properties; - - REGISTER_SPL_STD_CLASS_EX(array_it, spl_array_object_new, spl_array_it_class_functions); - REGISTER_SPL_IMPLEMENT(array_it, sequence_assoc); - memcpy(&spl_array_it_handlers, &spl_array_handlers, sizeof(zend_object_handlers)); - spl_array_it_handlers.get_class_entry = spl_array_it_get_ce; + REGISTER_SPL_INTERFACE(ArrayRead); + + REGISTER_SPL_INTERFACE(ArrayAccess); + zend_class_implements(spl_ce_ArrayAccess TSRMLS_CC, 1, spl_ce_ArrayRead); + + REGISTER_SPL_STD_CLASS_EX(ArrayClass, spl_array_object_new, spl_funcs_ArrayClass); + zend_class_implements(spl_ce_ArrayClass TSRMLS_CC, 1, zend_ce_aggregate); + memcpy(&spl_handler_ArrayClass, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + spl_handler_ArrayClass.clone_obj = spl_array_object_clone; + spl_handler_ArrayClass.read_dimension = spl_array_read_dimension; + spl_handler_ArrayClass.write_dimension = spl_array_write_dimension; + spl_handler_ArrayClass.unset_dimension = spl_array_unset_dimension; + spl_handler_ArrayClass.get_properties = spl_array_get_properties; + + REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator); + zend_class_implements(spl_ce_ArrayIterator TSRMLS_CC, 1, zend_ce_iterator); + memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayClass, sizeof(zend_object_handlers)); return SUCCESS; } @@ -566,7 +312,7 @@ PHP_MINIT_FUNCTION(spl_array) /* {{{ proto void spl_array::__construct(array|object ar = array()) proto void spl_array_it::__construct(array|object ar = array()) Cronstructs a new array iterator from a path. */ -SPL_CLASS_FUNCTION(array, __construct) +SPL_METHOD(Array, __construct) { zval *object = getThis(); spl_array_object *intern; @@ -598,9 +344,9 @@ SPL_CLASS_FUNCTION(array, __construct) } /* }}} */ -/* {{{ proto spl_array_it|NULL spl_array::newIterator() - Create a new iterator from a spl_array instance */ -SPL_CLASS_FUNCTION(array, newIterator) +/* {{{ proto spl_array_it|NULL ArrayClass::getIterator() + Create a new iterator from a ArrayClass instance */ +SPL_METHOD(Array, getIterator) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -613,7 +359,7 @@ SPL_CLASS_FUNCTION(array, newIterator) } return_value->type = IS_OBJECT; - return_value->value.obj = spl_array_object_new_ex(spl_ce_array_it, &iterator, intern TSRMLS_CC); + return_value->value.obj = spl_array_object_new_ex(spl_ce_ArrayIterator, &iterator, intern TSRMLS_CC); return_value->refcount = 1; return_value->is_ref = 1; } @@ -643,7 +389,7 @@ ZEND_API int spl_hash_pos_exists(spl_array_object * intern TSRMLS_DC) /* {{{ proto void spl_array_it::rewind() Rewind array back to the start */ -SPL_CLASS_FUNCTION(array, rewind) +SPL_METHOD(Array, rewind) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -660,7 +406,7 @@ SPL_CLASS_FUNCTION(array, rewind) /* {{{ proto mixed|false spl_array_it::current() Return current array entry */ -SPL_CLASS_FUNCTION(array, current) +SPL_METHOD(Array, current) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -687,7 +433,7 @@ SPL_CLASS_FUNCTION(array, current) /* {{{ proto mixed|false spl_array_it::key() Return current array key */ -SPL_CLASS_FUNCTION(array, key) +SPL_METHOD(Array, key) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -721,7 +467,7 @@ SPL_CLASS_FUNCTION(array, key) /* {{{ proto void spl_array_it::next() Move to next entry */ -SPL_CLASS_FUNCTION(array, next) +SPL_METHOD(Array, next) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); @@ -742,7 +488,7 @@ SPL_CLASS_FUNCTION(array, next) /* {{{ proto bool spl_array_it::hasMore() Check whether array contains more entries */ -SPL_CLASS_FUNCTION(array, hasMore) +SPL_METHOD(Array, hasMore) { zval *object = getThis(); spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC); |