2003-05-02 07:28:28 +08:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2003-06-13 03:30:54 +08:00
|
|
|
| PHP Version 5 |
|
2003-05-02 07:28:28 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2003-06-13 03:30:54 +08:00
|
|
|
| Copyright (c) 1997-2003 The PHP Group |
|
2003-05-02 07:28:28 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2003-06-13 03:30:54 +08:00
|
|
|
| This source file is subject to version 3.0 of the PHP license, |
|
2003-05-02 07:28:28 +08:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-13 03:30:54 +08:00
|
|
|
| available through the world-wide-web at the following url: |
|
|
|
|
| http://www.php.net/license/3_0.txt. |
|
2003-05-02 07:28:28 +08:00
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
| Authors: Marcus Boerger <helly@php.net> |
|
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "php.h"
|
|
|
|
#include "php_ini.h"
|
|
|
|
#include "ext/standard/info.h"
|
|
|
|
#include "zend_compile.h"
|
|
|
|
#include "zend_execute_locks.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)
|
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
/* {{{ spl_fetch_dimension_address */
|
|
|
|
int spl_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
|
2003-05-02 07:28:28 +08:00
|
|
|
{
|
2003-07-16 17:48:36 +08:00
|
|
|
zval **obj;
|
|
|
|
zend_class_entry *obj_ce;
|
|
|
|
spl_is_a is_a;
|
2003-05-02 07:28:28 +08:00
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
obj = spl_get_zval_ptr_ptr(op1, Ts TSRMLS_CC);
|
2003-05-02 07:28:28 +08:00
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
if (!obj || (obj_ce = spl_get_class_entry(*obj TSRMLS_CC)) == NULL) {
|
|
|
|
return 1;
|
2003-05-02 07:28:28 +08:00
|
|
|
}
|
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
is_a = spl_implements(obj_ce);
|
2003-05-02 07:28:28 +08:00
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
if (is_a & SPL_IS_A_ARRAY_READ) {
|
2003-05-02 07:28:28 +08:00
|
|
|
zval **retval = &(T(result->u.var).var.ptr);
|
|
|
|
zval *dim = spl_get_zval_ptr(op2, Ts, &EG(free_op2) TSRMLS_CC);
|
|
|
|
zval *exists;
|
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
spl_begin_method_call_arg_ex1(obj, obj_ce, NULL, "exists", sizeof("exists")-1, &exists, dim TSRMLS_CC);
|
2003-05-02 07:28:28 +08:00
|
|
|
if (!i_zend_is_true(exists)) {
|
|
|
|
if (type == BP_VAR_R || type == BP_VAR_RW) {
|
|
|
|
SEPARATE_ZVAL(&dim);
|
|
|
|
convert_to_string_ex(&dim);
|
2003-07-16 17:48:36 +08:00
|
|
|
zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(dim));
|
2003-05-02 07:28:28 +08:00
|
|
|
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) {
|
2003-07-16 17:48:36 +08:00
|
|
|
spl_begin_method_call_arg_ex1(obj, obj_ce, NULL, "get", sizeof("get")-1, retval, dim TSRMLS_CC);
|
2003-05-02 07:28:28 +08:00
|
|
|
}
|
|
|
|
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) {
|
|
|
|
PZVAL_LOCK(*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
|
|
|
|
/* }}} */
|
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
static inline zval **spl_get_obj_zval_ptr_ptr(znode *op, temp_variable *Ts, int type TSRMLS_DC)
|
2003-05-02 07:28:28 +08:00
|
|
|
{
|
2003-07-16 17:48:36 +08:00
|
|
|
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);
|
2003-05-02 07:28:28 +08:00
|
|
|
} else {
|
2003-07-16 17:48:36 +08:00
|
|
|
zend_error(E_ERROR, "Using $this when not in object context");
|
2003-05-02 07:28:28 +08:00
|
|
|
}
|
|
|
|
}
|
2003-07-16 17:48:36 +08:00
|
|
|
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);
|
2003-05-02 07:28:28 +08:00
|
|
|
}
|
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
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_begin_method_call_arg_ex2(obj, obj_ce, NULL, "set", sizeof("set")-1, &retval, index, value TSRMLS_CC);
|
2003-05-02 07:28:28 +08:00
|
|
|
|
2003-07-16 17:48:36 +08:00
|
|
|
if (index == &tmp) {
|
|
|
|
zval_dtor(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE_OP(Ts, op2, EG(free_op2));
|
|
|
|
if (&EX(opline)->result) {
|
2003-07-16 18:41:43 +08:00
|
|
|
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 {
|
|
|
|
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);
|
2003-07-16 17:48:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EX(opline)++;
|
|
|
|
NEXT_OPCODE();
|
|
|
|
}
|
|
|
|
ZEND_EXECUTE_HOOK_ORIGINAL(ZEND_ASSIGN_DIM);
|
2003-05-02 07:28:28 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
|
|
|
* vim600: fdm=marker
|
|
|
|
* vim: noet sw=4 ts=4
|
|
|
|
*/
|