mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Update and remove parts no longer possible
This commit is contained in:
parent
c03bd010c3
commit
15097151f4
9 changed files with 120 additions and 496 deletions
|
@ -56,7 +56,7 @@ zend_module_entry spl_module_entry = {
|
|||
PHP_RINIT(spl),
|
||||
PHP_RSHUTDOWN(spl),
|
||||
PHP_MINFO(spl),
|
||||
"0.1",
|
||||
"0.2",
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
};
|
||||
/* }}} */
|
||||
|
@ -69,11 +69,6 @@ zend_class_entry *spl_ce_forward_assoc;
|
|||
zend_class_entry *spl_ce_sequence_assoc;
|
||||
zend_class_entry *spl_ce_array_read;
|
||||
zend_class_entry *spl_ce_array_access;
|
||||
zend_class_entry *spl_ce_array_access_ex;
|
||||
zend_class_entry *spl_ce_array_writer;
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
zend_class_entry *spl_ce_array_writer_default;
|
||||
#endif /* SPL_ARRAY_WRITE */
|
||||
|
||||
/* {{{ spl_functions_none
|
||||
*/
|
||||
|
@ -82,17 +77,6 @@ function_entry spl_functions_none[] = {
|
|||
};
|
||||
/* }}} */
|
||||
|
||||
static unsigned char first_of_two_force_ref[] = { 2, BYREF_FORCE, BYREF_NONE };
|
||||
|
||||
/* {{{ spl_array_writer_funcs
|
||||
*/
|
||||
function_entry spl_array_writer_funcs[] = {
|
||||
SPL_CLASS_FE(array_writer_default, __construct, first_of_two_force_ref)
|
||||
SPL_CLASS_FE(array_writer_default, set, NULL)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_init_globals
|
||||
*/
|
||||
static void spl_init_globals(zend_spl_globals *spl_globals)
|
||||
|
@ -110,7 +94,7 @@ static void spl_init_globals(zend_spl_globals *spl_globals)
|
|||
#endif
|
||||
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
ZEND_EXECUTE_HOOK(ZEND_ASSIGN);
|
||||
ZEND_EXECUTE_HOOK(ZEND_ASSIGN_DIM);
|
||||
#endif /* SPL_ARRAY_WRITE */
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -152,18 +136,6 @@ PHP_MINIT_FUNCTION(spl)
|
|||
REGISTER_SPL_IMPLEMENT(array_access, array_read);
|
||||
REGISTER_SPL_INTF_FUNC(array_access, set);
|
||||
|
||||
REGISTER_SPL_INTERFACE(array_access_ex);
|
||||
REGISTER_SPL_IMPLEMENT(array_access_ex, array_access);
|
||||
REGISTER_SPL_INTF_FUNC(array_access_ex, new_writer);
|
||||
|
||||
REGISTER_SPL_INTERFACE(array_writer);
|
||||
REGISTER_SPL_INTF_FUNC(array_writer, set);
|
||||
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
REGISTER_SPL_STD_CLASS(array_writer_default, spl_array_writer_default_create);
|
||||
REGISTER_SPL_FUNCTIONS(array_writer_default, spl_array_writer_funcs);
|
||||
#endif
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -203,7 +175,7 @@ PHP_MSHUTDOWN_FUNCTION(spl)
|
|||
#endif
|
||||
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
ZEND_EXECUTE_HOOK_RESTORE(ZEND_ASSIGN);
|
||||
ZEND_EXECUTE_HOOK_RESTORE(ZEND_ASSIGN_DIM);
|
||||
#endif /* SPL_ARRAY_WRITE */
|
||||
|
||||
return SUCCESS;
|
||||
|
@ -240,8 +212,6 @@ PHP_MINFO_FUNCTION(spl)
|
|||
php_info_print_table_row(2, "sequence_assoc", foreach);
|
||||
php_info_print_table_row(2, "array_read", array_read);
|
||||
php_info_print_table_row(2, "array_access", array_write);
|
||||
php_info_print_table_row(2, "array_access_ex", array_write);
|
||||
php_info_print_table_row(2, "array_writer", array_write);
|
||||
php_info_print_table_end();
|
||||
}
|
||||
/* }}} */
|
||||
|
@ -295,12 +265,6 @@ PHP_FUNCTION(spl_classes)
|
|||
SPL_ADD_CLASS(sequence_assoc);
|
||||
SPL_ADD_CLASS(array_read);
|
||||
SPL_ADD_CLASS(array_access);
|
||||
SPL_ADD_CLASS(array_access_ex);
|
||||
SPL_ADD_CLASS(array_writer);
|
||||
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
SPL_ADD_CLASS(array_writer_default);
|
||||
#endif
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ ZEND_BEGIN_MODULE_GLOBALS(spl)
|
|||
ZEND_EXECUTE_HOOK_PTR(ZEND_FETCH_DIM_RW);
|
||||
#endif
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
ZEND_EXECUTE_HOOK_PTR(ZEND_ASSIGN);
|
||||
ZEND_EXECUTE_HOOK_PTR(ZEND_ASSIGN_DIM);
|
||||
#endif
|
||||
ZEND_END_MODULE_GLOBALS(spl)
|
||||
|
||||
|
@ -90,11 +90,6 @@ extern zend_class_entry *spl_ce_forward_assoc;
|
|||
extern zend_class_entry *spl_ce_sequence_assoc;
|
||||
extern zend_class_entry *spl_ce_array_read;
|
||||
extern zend_class_entry *spl_ce_array_access;
|
||||
extern zend_class_entry *spl_ce_array_access_ex;
|
||||
extern zend_class_entry *spl_ce_array_writer;
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
extern zend_class_entry *spl_ce_array_writer_default;
|
||||
#endif /* SPL_ARRAY_WRITE */
|
||||
|
||||
PHP_FUNCTION(spl_classes);
|
||||
PHP_FUNCTION(class_parents);
|
||||
|
|
|
@ -226,79 +226,11 @@ interface spl_array_read {
|
|||
}
|
||||
\endcode
|
||||
*/
|
||||
interface spl_array_access extends spl_array_read {
|
||||
interface spl_array_access implements spl_array_read {
|
||||
|
||||
/*! Set the value identified by $index to $value.
|
||||
*/
|
||||
function set($value, $index);
|
||||
}
|
||||
|
||||
/*! \brief array read/write access with customized array_writer
|
||||
*
|
||||
* The internal structure requires that write access via interfaces
|
||||
* is divided into two parts. First the index is used to create an
|
||||
* array_writer which will later receive the new value and calls the
|
||||
* containers set() method with appropriate parameters.
|
||||
*
|
||||
* Sometimes it is helpfull to overwrite this behavior and have your
|
||||
* own implementation for the array_writer.
|
||||
*
|
||||
* The following example shows how to use a customized array_writer:
|
||||
* \code
|
||||
class array_emulation_ex extends array_emulation implemets spl_array_access_ex {
|
||||
private $last_index = NULL;
|
||||
function new_writer($index) {
|
||||
$last_index = $index;
|
||||
return new array_write(&$this, $index);
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
interface spl_array_access_ex extends spl_array_access {
|
||||
|
||||
/*! Create an array_writer interface for the specified index.
|
||||
*
|
||||
* If your container uses array_access instead of array_access_ex
|
||||
* the following code would be equal to the internal new_writer()
|
||||
* method:
|
||||
\code
|
||||
function new_writer($index) {
|
||||
return new array_write(&$this, $index);
|
||||
}
|
||||
\endcode
|
||||
*/
|
||||
function new_writer($index);
|
||||
}
|
||||
|
||||
/*! \brief array writer interface
|
||||
*
|
||||
* for every write access to an array_access instance an array_writer
|
||||
* is created which receives the originating object and the index as
|
||||
* parameters for the constructor call.
|
||||
*
|
||||
* The following shows the equivalent php code for the default
|
||||
* implementation array_write.
|
||||
* \code
|
||||
class array_write implements array_writer {
|
||||
private $obj;
|
||||
private $idx;
|
||||
function __construct(&$obj, $index = null) {
|
||||
$this->obj = $obj;
|
||||
$this->idx = $index;
|
||||
}
|
||||
function set($value) {
|
||||
return $this->obj->set($this->idx, $value);
|
||||
}
|
||||
}
|
||||
\endcode
|
||||
*
|
||||
* See array_access for more.
|
||||
*/
|
||||
interface spl_array_writer {
|
||||
|
||||
/*! Set the corresponding value to $value.
|
||||
*/
|
||||
function set($value);
|
||||
}
|
||||
|
||||
?>
|
|
@ -46,139 +46,32 @@
|
|||
#define AI_PTR_2_PTR_PTR(ai) \
|
||||
(ai).ptr_ptr = &((ai).ptr)
|
||||
|
||||
/* {{{ spl_array_writer_default stuff */
|
||||
typedef struct {
|
||||
zval *obj;
|
||||
zval *idx;
|
||||
int locked;
|
||||
} spl_array_writer_object;
|
||||
|
||||
static zend_class_entry *spl_array_writer_default_get_class(zval *object TSRMLS_DC)
|
||||
{
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
return spl_ce_array_writer_default;
|
||||
#else
|
||||
return (zend_class_entry *)1; /* force an error here: this ensures not equal */
|
||||
#endif
|
||||
}
|
||||
|
||||
static zend_object_handlers spl_array_writer_default_handlers = {
|
||||
ZEND_OBJECTS_STORE_HANDLERS,
|
||||
|
||||
NULL, /* read_property */
|
||||
NULL, /* write_property */
|
||||
NULL, /* get_property_ptr */
|
||||
NULL, /* get_property_zval_ptr */
|
||||
NULL, /* get */
|
||||
NULL, /* set */
|
||||
NULL, /* has_property */
|
||||
NULL, /* unset_property */
|
||||
NULL, /* get_properties */
|
||||
NULL, /* get_method */
|
||||
NULL, /* call_method */
|
||||
NULL, /* get_constructor */
|
||||
spl_array_writer_default_get_class, /* get_class_entry */
|
||||
NULL, /* get_class_name */
|
||||
NULL /* compare_objects */
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_array_writer_dtor */
|
||||
void spl_array_writer_default_dtor(void *object, zend_object_handle handle TSRMLS_DC)
|
||||
{
|
||||
spl_array_writer_object *writer = (spl_array_writer_object*) object;
|
||||
|
||||
if (writer->obj)
|
||||
{
|
||||
writer->obj->refcount--;
|
||||
/* DELETE_ZVAL(writer->obj); */
|
||||
}
|
||||
if (writer->idx)
|
||||
{
|
||||
if (writer->locked) {
|
||||
PZVAL_UNLOCK(writer->idx);
|
||||
} else {
|
||||
writer->idx->refcount--;
|
||||
DELETE_ZVAL(writer->idx);
|
||||
}
|
||||
}
|
||||
efree(writer);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_array_writer_default_create */
|
||||
zend_object_value spl_array_writer_default_create(zend_class_entry *class_type TSRMLS_DC)
|
||||
{
|
||||
zend_object_value retval;
|
||||
spl_array_writer_object *intern;
|
||||
|
||||
intern = ecalloc(sizeof(spl_array_writer_object), 1);
|
||||
|
||||
retval.handle = zend_objects_store_put(intern, spl_array_writer_default_dtor, NULL TSRMLS_CC);
|
||||
retval.handlers = &spl_array_writer_default_handlers;
|
||||
|
||||
return retval;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_array_writer_default_set */
|
||||
void spl_array_writer_default_set(zval *object, zval *newval, zval **retval TSRMLS_DC)
|
||||
{
|
||||
spl_array_writer_object *writer;
|
||||
|
||||
writer = (spl_array_writer_object *) zend_object_store_get_object(object TSRMLS_CC);
|
||||
spl_begin_method_call_arg_ex2(&writer->obj, NULL, NULL, "set", sizeof("set")-1, retval, writer->idx, newval TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ SPL_CLASS_FUNCTION(array_writer_default, __construct) */
|
||||
SPL_CLASS_FUNCTION(array_writer_default, __construct)
|
||||
{
|
||||
zval *object = getThis();
|
||||
zval *obj, *idx;
|
||||
spl_array_writer_object *writer;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &obj, &idx) == FAILURE) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to parse parameters");
|
||||
return;
|
||||
}
|
||||
writer = (spl_array_writer_object *) zend_object_store_get_object(object TSRMLS_CC);
|
||||
writer->obj = obj; obj->refcount++;
|
||||
writer->idx = idx; idx->refcount++;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ SPL_CLASS_FUNCTION(array_writer_default, set) */
|
||||
SPL_CLASS_FUNCTION(array_writer_default, set)
|
||||
{
|
||||
zval *object = getThis();
|
||||
zval *newval;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &newval) == FAILURE) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to parse parameters");
|
||||
return;
|
||||
}
|
||||
spl_array_writer_default_set(object, newval, &return_value TSRMLS_CC);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ spl_fetch_dimension_address */
|
||||
int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
|
||||
{
|
||||
zval **container_ptr = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC);
|
||||
zval **obj;
|
||||
zend_class_entry *obj_ce;
|
||||
spl_is_a is_a;
|
||||
|
||||
if (spl_is_instance_of(container_ptr, spl_ce_array_read TSRMLS_CC)) {
|
||||
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;
|
||||
|
||||
/*ALLOC_ZVAL(exists); not needed */
|
||||
spl_begin_method_call_arg_ex1(container_ptr, NULL, NULL, "exists", sizeof("exists")-1, &exists, dim TSRMLS_CC);
|
||||
spl_begin_method_call_arg_ex1(obj, obj_ce, NULL, "exists", sizeof("exists")-1, &exists, dim TSRMLS_CC);
|
||||
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));
|
||||
zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(dim));
|
||||
DELETE_ZVAL(dim);
|
||||
}
|
||||
if (type == BP_VAR_R || type == BP_VAR_IS) {
|
||||
|
@ -192,37 +85,8 @@ int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_vari
|
|||
}
|
||||
DELETE_RET_ZVAL(exists);
|
||||
if (type == BP_VAR_R || type == BP_VAR_IS) {
|
||||
spl_begin_method_call_arg_ex1(container_ptr, NULL, NULL, "get", sizeof("get")-1, retval, dim TSRMLS_CC);
|
||||
(*retval)->refcount--;
|
||||
} else
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
if (spl_is_instance_of(container_ptr, spl_ce_array_access_ex TSRMLS_CC)) {
|
||||
/* array_access_ex instaces have their own way of creating an access_writer */
|
||||
spl_begin_method_call_arg_ex1(container_ptr, NULL, NULL, "new_writer", sizeof("new_writer")-1, retval, dim TSRMLS_CC);
|
||||
T(result->u.var).var.ptr = *retval;
|
||||
AI_PTR_2_PTR_PTR(T(result->u.var).var);
|
||||
SELECTIVE_PZVAL_LOCK(*retval, result);
|
||||
} else if (spl_is_instance_of(container_ptr, spl_ce_array_access TSRMLS_CC)) {
|
||||
/* array_access instances create the default array_writer: array_write */
|
||||
spl_array_writer_object *writer;
|
||||
spl_instanciate(spl_ce_array_writer_default, retval TSRMLS_CC);
|
||||
T(result->u.var).var.ptr = *retval;
|
||||
AI_PTR_2_PTR_PTR(T(result->u.var).var);
|
||||
writer = (spl_array_writer_object *) zend_object_store_get_object(*retval TSRMLS_CC);
|
||||
writer->obj = *container_ptr;
|
||||
writer->obj->refcount++;
|
||||
writer->idx = dim;
|
||||
PZVAL_LOCK(writer->idx);
|
||||
writer->locked = 1;
|
||||
SELECTIVE_PZVAL_LOCK(*retval, result);
|
||||
} else {
|
||||
zend_error(E_ERROR, "Object must implement spl_array_access for write access");
|
||||
retval = &EG(error_zval_ptr);
|
||||
spl_begin_method_call_arg_ex1(obj, obj_ce, NULL, "get", sizeof("get")-1, retval, dim TSRMLS_CC);
|
||||
}
|
||||
SELECTIVE_PZVAL_LOCK(*retval, result);
|
||||
#else
|
||||
zend_error(E_ERROR, "SPL compiled without array write hook");
|
||||
#endif
|
||||
FREE_OP(Ts, op2, EG(free_op2));
|
||||
return 0;
|
||||
}
|
||||
|
@ -279,66 +143,90 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW)
|
|||
#endif
|
||||
/* }}} */
|
||||
|
||||
/* {{{ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN) */
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN)
|
||||
static inline zval **spl_get_obj_zval_ptr_ptr(znode *op, temp_variable *Ts, int type TSRMLS_DC)
|
||||
{
|
||||
zval **writer = spl_get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
||||
zval *newval, *retval, *target;
|
||||
znode *result;
|
||||
|
||||
if (writer && *writer && Z_TYPE_PP(writer) == IS_OBJECT) {
|
||||
/* optimization: do pre checks and only test for handlers in case of
|
||||
* spl_array_writer_default, for spl_array_writer we must use the
|
||||
* long way of calling spl_instance
|
||||
* if (spl_is_instance_of(writer, spl_ce_array_writer_default TSRMLS_CC))
|
||||
*/
|
||||
if ((*writer)->value.obj.handlers == &spl_array_writer_default_handlers) {
|
||||
newval = spl_get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2) TSRMLS_CC);
|
||||
spl_array_writer_default_set(*writer, newval, &retval TSRMLS_CC);
|
||||
} else if (spl_is_instance_of(writer, spl_ce_array_writer TSRMLS_CC)) {
|
||||
newval = spl_get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2) TSRMLS_CC);
|
||||
spl_begin_method_call_arg_ex1(writer, NULL, NULL, "set", sizeof("set")-1, &retval, newval TSRMLS_CC);
|
||||
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_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN);
|
||||
zend_error(E_ERROR, "Using $this when not in object context");
|
||||
}
|
||||
} else {
|
||||
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN);
|
||||
}
|
||||
spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
||||
return spl_get_zval_ptr_ptr(op, Ts TSRMLS_CC);
|
||||
}
|
||||
|
||||
result = &EX(opline)->result;
|
||||
if (result) {
|
||||
if (retval->refcount<2) {
|
||||
if ((*writer)->value.obj.handlers == &spl_array_writer_default_handlers) {
|
||||
spl_array_writer_object *object = (spl_array_writer_object *) zend_object_store_get_object(*writer TSRMLS_CC);
|
||||
target = object->obj;
|
||||
} else {
|
||||
target = *writer;
|
||||
}
|
||||
zend_error(E_WARNING, "Method %s::set() did not return a value, using NULL", Z_OBJCE_P(target)->name);
|
||||
DELETE_ZVAL(retval);
|
||||
DELETE_ZVAL(newval);
|
||||
/* Unfortunately it doesn't work when trying to return newval.
|
||||
* But anyhow it wouldn't make sense...and confuse reference counting and such.
|
||||
*/
|
||||
retval = &EG(uninitialized_zval);
|
||||
} else {
|
||||
retval->refcount--;
|
||||
}
|
||||
EX_T(EX(opline)->result.u.var).var.ptr = retval;
|
||||
AI_PTR_2_PTR_PTR(EX_T(EX(opline)->result.u.var).var);
|
||||
SELECTIVE_PZVAL_LOCK(retval, result);
|
||||
} else {
|
||||
retval->refcount = 1;
|
||||
DELETE_ZVAL(retval);
|
||||
/* {{{ 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);
|
||||
}
|
||||
|
||||
(*writer)->refcount = 1;
|
||||
DELETE_ZVAL(*writer);
|
||||
FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
|
||||
is_a = spl_implements(obj_ce);
|
||||
|
||||
NEXT_OPCODE();
|
||||
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_begin_method_call_arg_ex2(obj, obj_ce, NULL, "set", sizeof("set")-1, &retval, index, value TSRMLS_CC);
|
||||
|
||||
if (index == &tmp) {
|
||||
zval_dtor(index);
|
||||
}
|
||||
|
||||
FREE_OP(Ts, op2, EG(free_op2));
|
||||
if (&EX(opline)->result) {
|
||||
EX_T(EX(opline)->result.u.var).var.ptr = retval;
|
||||
EX_T(EX(opline)->result.u.var).var.ptr_ptr = NULL;/*&EX_T(EX(opline)->result.u.var).var.ptr;*/
|
||||
SELECTIVE_PZVAL_LOCK(retval, &EX(opline)->result);
|
||||
}
|
||||
|
||||
EX(opline)++;
|
||||
NEXT_OPCODE();
|
||||
}
|
||||
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM);
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
|
|
@ -29,14 +29,9 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FETCH_DIM_RW);
|
|||
#endif
|
||||
|
||||
#ifdef SPL_ARRAY_WRITE
|
||||
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN);
|
||||
ZEND_EXECUTE_HOOK_FUNCTION(ZEND_ASSIGN_DIM);
|
||||
#endif
|
||||
|
||||
SPL_CLASS_FUNCTION(array_writer_default, __construct);
|
||||
SPL_CLASS_FUNCTION(array_writer_default, set);
|
||||
|
||||
zend_object_value spl_array_writer_default_create(zend_class_entry *class_type TSRMLS_DC);
|
||||
|
||||
#endif /* SPL_ARRAY_H */
|
||||
|
||||
/*
|
||||
|
|
|
@ -158,10 +158,12 @@ spl_is_a spl_implements(zend_class_entry *ce)
|
|||
register zend_class_entry **pce = ce->interfaces;
|
||||
|
||||
while (i--) {
|
||||
if (*pce == spl_ce_iterator) is_a |= SPL_IS_A_ITERATOR;
|
||||
else if (*pce == spl_ce_forward) is_a |= SPL_IS_A_FORWARD;
|
||||
else if (*pce == spl_ce_assoc) is_a |= SPL_IS_A_ASSOC;
|
||||
else if (*pce == spl_ce_sequence) is_a |= SPL_IS_A_SEQUENCE;
|
||||
if (*pce == spl_ce_iterator) is_a |= SPL_IS_A_ITERATOR;
|
||||
else if (*pce == spl_ce_forward) is_a |= SPL_IS_A_FORWARD;
|
||||
else if (*pce == spl_ce_assoc) is_a |= SPL_IS_A_ASSOC;
|
||||
else if (*pce == spl_ce_sequence) is_a |= SPL_IS_A_SEQUENCE;
|
||||
else if (*pce == spl_ce_array_read) is_a |= SPL_IS_A_ARRAY_READ;
|
||||
else if (*pce == spl_ce_array_access) is_a |= SPL_IS_A_ARRAY_ACCESS;
|
||||
pce++;
|
||||
}
|
||||
return is_a;
|
||||
|
|
|
@ -50,10 +50,10 @@ static inline zend_class_entry *spl_get_class_entry(zval *obj TSRMLS_DC)
|
|||
/* }}} */
|
||||
|
||||
/* {{{ spl_begin_method_call_arg */
|
||||
static inline int spl_begin_method_call_arg(zval **ce, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int fname_len, zval *retval, zval *arg1 TSRMLS_DC)
|
||||
static inline int spl_begin_method_call_arg(zval **obj, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int fname_len, zval *retval, zval *arg1 TSRMLS_DC)
|
||||
{
|
||||
zval *local_retval;
|
||||
int ret = spl_call_method(ce, obj_ce, fn_proxy, function_name, fname_len, &local_retval, NULL TSRMLS_CC, 1, arg1);
|
||||
int ret = spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, &local_retval, NULL TSRMLS_CC, 1, arg1);
|
||||
if (local_retval) {
|
||||
COPY_PZVAL_TO_ZVAL(*retval, local_retval);
|
||||
} else {
|
||||
|
@ -64,10 +64,10 @@ static inline int spl_begin_method_call_arg(zval **ce, zend_class_entry *obj_ce,
|
|||
/* }}} */
|
||||
|
||||
/* {{{ spl_begin_method_call_no_retval */
|
||||
static inline int spl_begin_method_call_no_retval(zval **ce, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int fname_len TSRMLS_DC)
|
||||
static inline int spl_begin_method_call_no_retval(zval **obj, zend_class_entry *obj_ce, zend_function **fn_proxy, char *function_name, int fname_len TSRMLS_DC)
|
||||
{
|
||||
zval *retval;
|
||||
int ret = spl_call_method(ce, obj_ce, fn_proxy, function_name, fname_len, &retval, NULL TSRMLS_CC, 0);
|
||||
int ret = spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, &retval, NULL TSRMLS_CC, 0);
|
||||
if (retval) {
|
||||
zval_dtor(retval);
|
||||
FREE_ZVAL(retval);
|
||||
|
@ -76,14 +76,14 @@ static inline int spl_begin_method_call_no_retval(zval **ce, zend_class_entry *o
|
|||
}
|
||||
/* }}} */
|
||||
|
||||
#define spl_begin_method_call_ex(ce, obj_ce, fn_proxy, function_name, fname_len, retval) \
|
||||
spl_call_method(ce, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 0)
|
||||
#define spl_begin_method_call_ex(obj, obj_ce, fn_proxy, function_name, fname_len, retval) \
|
||||
spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 0)
|
||||
|
||||
#define spl_begin_method_call_arg_ex1(ce, obj_ce, fn_proxy, function_name, fname_len, retval, arg1) \
|
||||
spl_call_method(ce, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 1, arg1)
|
||||
#define spl_begin_method_call_arg_ex1(obj, obj_ce, fn_proxy, function_name, fname_len, retval, arg1) \
|
||||
spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 1, arg1)
|
||||
|
||||
#define spl_begin_method_call_arg_ex2(ce, obj_ce, fn_proxy, function_name, fname_len, retval, arg1, arg2) \
|
||||
spl_call_method(ce, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 2, arg1, arg2)
|
||||
#define spl_begin_method_call_arg_ex2(obj, obj_ce, fn_proxy, function_name, fname_len, retval, arg1, arg2) \
|
||||
spl_call_method(obj, obj_ce, fn_proxy, function_name, fname_len, retval, NULL TSRMLS_CC, 2, arg1, arg2)
|
||||
|
||||
void spl_instanciate(zend_class_entry *pce, zval **object TSRMLS_DC);
|
||||
int spl_instanciate_arg_ex2(zend_class_entry *pce, zval **retval, zval *arg1, zval *arg2, HashTable *symbol_table TSRMLS_DC);
|
||||
|
@ -95,10 +95,12 @@ zval * spl_get_zval_ptr(znode *node, temp_variable *Ts, zval **should_free TSRML
|
|||
int spl_is_instance_of(zval **obj, zend_class_entry *ce TSRMLS_DC);
|
||||
|
||||
typedef enum {
|
||||
SPL_IS_A_ITERATOR = 1,
|
||||
SPL_IS_A_FORWARD = 2,
|
||||
SPL_IS_A_ASSOC = 4,
|
||||
SPL_IS_A_SEQUENCE = 8
|
||||
SPL_IS_A_ITERATOR = 0x01,
|
||||
SPL_IS_A_FORWARD = 0x02,
|
||||
SPL_IS_A_ASSOC = 0x04,
|
||||
SPL_IS_A_SEQUENCE = 0x08,
|
||||
SPL_IS_A_ARRAY_READ = 0x10,
|
||||
SPL_IS_A_ARRAY_ACCESS = 0x20
|
||||
} spl_is_a;
|
||||
|
||||
spl_is_a spl_implements(zend_class_entry *ce);
|
||||
|
|
|
@ -69,8 +69,8 @@ ZEND_EXECUTE_HOOK_FUNCTION(ZEND_FE_RESET)
|
|||
|
||||
if (is_a & SPL_IS_A_ITERATOR) {
|
||||
spl_unlock_zval_ptr_ptr(&EX(opline)->op1, EX(Ts) TSRMLS_CC);
|
||||
spl_begin_method_call_ex(obj, NULL, NULL, "new_iterator", sizeof("new_iterator")-1, &retval);
|
||||
obj_ce = instance_ce;
|
||||
spl_begin_method_call_ex(obj, obj_ce, NULL, "new_iterator", sizeof("new_iterator")-1, &retval);
|
||||
instance_ce = spl_get_class_entry(retval TSRMLS_CC);
|
||||
is_a = spl_implements(instance_ce);
|
||||
if (!(is_a & SPL_IS_A_FORWARD)) {
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
--TEST--
|
||||
SPL: array_access
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!extension_loaded("spl")) die("skip");
|
||||
if (!in_array("spl_array_access", spl_classes())) die("skip spl_array_access not present");
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
class array_write implements spl_array_writer {
|
||||
private $obj;
|
||||
private $idx;
|
||||
|
||||
function __construct(&$obj, $index = null) {
|
||||
$this->obj = &$obj;
|
||||
$this->idx = $index;
|
||||
}
|
||||
|
||||
function set($value) {
|
||||
echo __METHOD__ . "($value,".$this->idx.")\n";
|
||||
return $this->obj->set($this->idx, $value);
|
||||
}
|
||||
}
|
||||
|
||||
class c implements spl_array_access_ex {
|
||||
|
||||
public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
|
||||
|
||||
function new_writer($index) {
|
||||
return new array_write(&$this, $index);
|
||||
}
|
||||
|
||||
function exists($index) {
|
||||
echo __METHOD__ . "($index)\n";
|
||||
return array_key_exists($index, $this->a);
|
||||
}
|
||||
|
||||
function get($index) {
|
||||
echo __METHOD__ . "($index)\n";
|
||||
return $this->a[$index];
|
||||
}
|
||||
|
||||
function set($index, $newval) {
|
||||
echo __METHOD__ . "($index,$newval)\n";
|
||||
return $this->a[$index] = $newval;
|
||||
}
|
||||
}
|
||||
|
||||
$obj = new c();
|
||||
|
||||
var_dump($obj->a);
|
||||
|
||||
var_dump($obj[0]);
|
||||
var_dump($obj[1]);
|
||||
var_dump($obj[2]);
|
||||
var_dump($obj['4th']);
|
||||
var_dump($obj['5th']);
|
||||
var_dump($obj[6]);
|
||||
|
||||
echo "WRITE 1\n";
|
||||
$obj[1] = 'Changed 1';
|
||||
var_dump($obj[1]);
|
||||
echo "WRITE 2\n";
|
||||
$obj['4th'] = 'Changed 4th';
|
||||
var_dump($obj['4th']);
|
||||
echo "WRITE 3\n";
|
||||
$obj['5th'] = 'Added 5th';
|
||||
var_dump($obj['5th']);
|
||||
echo "WRITE 4\n";
|
||||
$obj[6] = 'Added 6';
|
||||
var_dump($obj[6]);
|
||||
|
||||
var_dump($obj[0]);
|
||||
var_dump($obj[2]);
|
||||
|
||||
$x = $obj[6] = 'changed 6';
|
||||
var_dump($obj[6]);
|
||||
var_dump($x);
|
||||
|
||||
print "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "1st"
|
||||
[1]=>
|
||||
int(1)
|
||||
[2]=>
|
||||
string(3) "3rd"
|
||||
["4th"]=>
|
||||
int(4)
|
||||
}
|
||||
c::exists(0)
|
||||
c::get(0)
|
||||
string(3) "1st"
|
||||
c::exists(1)
|
||||
c::get(1)
|
||||
int(1)
|
||||
c::exists(2)
|
||||
c::get(2)
|
||||
string(3) "3rd"
|
||||
c::exists(4th)
|
||||
c::get(4th)
|
||||
int(4)
|
||||
c::exists(5th)
|
||||
|
||||
Notice: Undefined index: 5th in %sarray_access_ex.php on line %d
|
||||
NULL
|
||||
c::exists(6)
|
||||
|
||||
Notice: Undefined index: 6 in %sarray_access_ex.php on line %d
|
||||
NULL
|
||||
WRITE 1
|
||||
c::exists(1)
|
||||
array_write::set(Changed 1,1)
|
||||
c::set(1,Changed 1)
|
||||
c::exists(1)
|
||||
c::get(1)
|
||||
string(9) "Changed 1"
|
||||
WRITE 2
|
||||
c::exists(4th)
|
||||
array_write::set(Changed 4th,4th)
|
||||
c::set(4th,Changed 4th)
|
||||
c::exists(4th)
|
||||
c::get(4th)
|
||||
string(11) "Changed 4th"
|
||||
WRITE 3
|
||||
c::exists(5th)
|
||||
array_write::set(Added 5th,5th)
|
||||
c::set(5th,Added 5th)
|
||||
c::exists(5th)
|
||||
c::get(5th)
|
||||
string(9) "Added 5th"
|
||||
WRITE 4
|
||||
c::exists(6)
|
||||
array_write::set(Added 6,6)
|
||||
c::set(6,Added 6)
|
||||
c::exists(6)
|
||||
c::get(6)
|
||||
string(7) "Added 6"
|
||||
c::exists(0)
|
||||
c::get(0)
|
||||
string(3) "1st"
|
||||
c::exists(2)
|
||||
c::get(2)
|
||||
string(3) "3rd"
|
||||
c::exists(6)
|
||||
array_write::set(changed 6,6)
|
||||
c::set(6,changed 6)
|
||||
c::exists(6)
|
||||
c::get(6)
|
||||
string(9) "changed 6"
|
||||
string(9) "changed 6"
|
||||
Done
|
Loading…
Add table
Add a link
Reference in a new issue