summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorStanislav Malyshev <stas@php.net>2002-02-07 14:08:43 +0000
committerStanislav Malyshev <stas@php.net>2002-02-07 14:08:43 +0000
commit6608f07322789bd0896b265c29e13c0c9f5d5898 (patch)
tree3149fb62b09cbea8d328df4d930e4cddb99aef03 /Zend
parent5e9b1634c68dc70bbc6480fddb303d8807a943d2 (diff)
downloadphp-git-6608f07322789bd0896b265c29e13c0c9f5d5898.tar.gz
Mega-commit: Enter the new object model
Note: only standard Zend objects are working now. This is definitely going to break custom objects like COM, Java, etc. - this will be fixed later. Also, this may break other things that access objects' internals directly.
Diffstat (limited to 'Zend')
-rw-r--r--Zend/Makefile.am2
-rw-r--r--Zend/OBJECTS2_HOWTO177
-rw-r--r--Zend/ZendTS.dsp8
-rw-r--r--Zend/zend.h24
-rw-r--r--Zend/zend_API.c26
-rw-r--r--Zend/zend_API.h4
-rw-r--r--Zend/zend_builtin_functions.c53
-rw-r--r--Zend/zend_compile.c8
-rw-r--r--Zend/zend_execute.c412
-rw-r--r--Zend/zend_execute.h4
-rw-r--r--Zend/zend_execute_API.c11
-rw-r--r--Zend/zend_globals.h1
-rw-r--r--Zend/zend_object_handlers.c257
-rw-r--r--Zend/zend_object_handlers.h73
-rw-r--r--Zend/zend_objects.c34
-rw-r--r--Zend/zend_objects.h14
-rw-r--r--Zend/zend_operators.c50
-rw-r--r--Zend/zend_operators.h8
-rw-r--r--Zend/zend_variables.c4
19 files changed, 825 insertions, 345 deletions
diff --git a/Zend/Makefile.am b/Zend/Makefile.am
index ba2180cc6c..4f73a2ac92 100644
--- a/Zend/Makefile.am
+++ b/Zend/Makefile.am
@@ -13,7 +13,7 @@ libZend_la_SOURCES=\
zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \
zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
- zend_ini.c zend_qsort.c zend_objects.c
+ zend_ini.c zend_qsort.c zend_objects.c zend_object_handlers.c
libZend_la_LDFLAGS =
libZend_la_LIBADD = @ZEND_EXTRA_LIBS@
diff --git a/Zend/OBJECTS2_HOWTO b/Zend/OBJECTS2_HOWTO
new file mode 100644
index 0000000000..9a0222e313
--- /dev/null
+++ b/Zend/OBJECTS2_HOWTO
@@ -0,0 +1,177 @@
+Creating an object
+------------------
+
+Object can be created in the following ways:
+
+1. As a result of a function call. E.g.:
+
+$foo = create_new_foo("parameter");
+$foo->run();
+
+The function should create a new zval, create new object and get the
+handle for it, set handle and handler table as needed. Note that the
+handle is the only ID of the object, so it should be enough to
+identify it.
+
+2. Overriding create_object handler for class. E.g.:
+
+$foo = new Java("some.Class.here", "parameter");
+$foo->run();
+
+The create_object handler function should create a new zval, create
+new object and get the handle for it, set handle and handler table as
+needed, and also provide constructor method that would handle
+constructor call. The get_constructor handler table entry should be
+used for that. Do not rely class entry's constructor, unless you refer
+to it from get_constructor handler.
+
+Object maintenance
+------------------
+
+The handlers add_ref and del_ref are called when a new zval referring
+to the object is created. This does not create a new object - both
+zvals still refer to the same object.
+
+clone_obj handler should create a new object, identical to an old one,
+but being a separate entity.
+
+delete_obj should destroy an object, all references to it become
+invalid.
+
+Object access - read
+--------------------
+
+get_property is used to read object's property. This value is not
+meant to be changed. The handler returns zval * with the value.
+
+Object access - write
+---------------------
+
+write_property is used to directly write object's property by
+name. This handler is not oftenly used by the engine itself, but may
+be used by some internal functions.
+
+get_property_ptr is used to obtain zval ** for future writing to
+it. If your object properties are stored as zval*, return real place
+where the property is stored. If the aren't, the best way is to create
+proxy object and handle it via get and set methods (see below).
+
+get and set handlers are used when engine needs to access the object
+as a value. E.g., in the following situation:
+
+$foo =& $obj->bar;
+$foo = 1;
+
+if $foo is an object (e.g., proxy object from get_property_ptr) it
+would be accessed using write handler.
+
+Object access - method call
+---------------------------
+
+get_method handler is used to find method description by name. It
+should set right type, function name and parameter mask for the
+method. If the type is ZEND_OVERLOADED_FUNCTION, the method would be
+called via call_method handler, otherwise it would be called with
+standard Zend means.
+
+get_constructor performs the same function as get_method, but for the
+object constructor.
+
+call_method handler is used to perform method call. Parameters are
+passed like to any other Zend internal function.
+
+Object - comparison
+-------------------
+
+Objects can be compared via compare_objects handler. This is used with
+== operation, === compares objects by handles, i.e., return true if
+and only if it's really the same object. Note that objects from
+different object types (i.e., having different handlers) can not be
+compared.
+
+Objects - reflection
+--------------------
+
+get_class_name is used to retrieve class name of the object. No other
+reflection functions are currently implemented.
+
+Objects - data structures and handlers
+---------------------------------------
+
+The object is represented by the following structure:
+
+struct _zend_object_value {
+ zend_object_handle handle;
+ zend_object_handlers *handlers;
+};
+
+handle is an ID of the object among the objects of the same type (not
+class!). The type of the object and how it behaves is determined by
+the handler table.
+
+typedef struct _zend_object_handlers {
+ zend_object_add_ref_t add_ref;
+ zend_object_del_ref_t del_ref;
+ zend_object_delete_obj_t delete_obj;
+ zend_object_clone_obj_t clone_obj;
+ zend_object_read_property_t read_property;
+ zend_object_write_property_t write_property;
+ zend_object_get_property_ptr_t get_property_ptr;
+ zend_object_get_t get;
+ zend_object_set_t set;
+ zend_object_has_property_t has_property;
+ zend_object_unset_property_t unset_property;
+ zend_object_get_properties_t get_properties;
+ zend_object_get_method_t get_method;
+ zend_object_call_method_t call_method;
+ zend_object_get_constructor_t get_constructor;
+ zend_object_get_class_name_t get_class_name;
+ zend_object_compare_t compare_objects;
+} zend_object_handlers;
+
+See zend_object_handlers.h for prototypes. All objects are passed as zval's.
+
+Handlers explained:
+
+add_ref - called when a copy of the object handle is created.
+
+del_ref - called when a copy of the object handle is destroyed.
+
+delete_obj - called when an object needs to be destroyed.
+
+clone_obj - called when a new object identical to an old one should be
+created (unlike Zend Engine 1, this never happens unless explicitly
+asked for).
+
+read_property - returns zval *, containing the value of the
+property. Is used when value of the property should be retrieved for
+reading.
+
+write_property - assigns value to certain property of the object.
+
+get_property_ptr - retrieves zval** for the property of the value, to
+be used for read and write. If object properties are not zval's
+natively, this method should create and return proxy object for use
+with get and set methods.
+
+get - retrieves zval* for object contents. To be used mainly with
+proxy objects from get_property_ptr, but also may be used for
+convert_to_* functions.
+
+set - sets value for object contents. To be used mainly with
+proxy objects from get_property_ptr.
+
+has_property - checks if the object has certain property set.
+
+unset_property - removes value for the property of the object
+
+get_method - retrieves description of the method
+
+call_method - calls the method (parameters should be put on stack like
+for any other PHP internal function).
+
+get_constructor - get description for the object constructor method
+
+get_class_name - get the name of the class the object belongs to
+
+compare_objects - compares if two objects are equal
diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp
index 573a41397e..d69cfa3e6b 100644
--- a/Zend/ZendTS.dsp
+++ b/Zend/ZendTS.dsp
@@ -212,6 +212,10 @@ SOURCE=.\zend_llist.c
# End Source File
# Begin Source File
+SOURCE=.\zend_object_handlers.c
+# End Source File
+# Begin Source File
+
SOURCE=.\zend_objects.c
# End Source File
# Begin Source File
@@ -360,6 +364,10 @@ SOURCE=.\zend_modules.h
# End Source File
# Begin Source File
+SOURCE=.\zend_object_handlers.h
+# End Source File
+# Begin Source File
+
SOURCE=.\zend_objects.h
# End Source File
# Begin Source File
diff --git a/Zend/zend.h b/Zend/zend.h
index c9251112bb..f6fd80bf61 100644
--- a/Zend/zend.h
+++ b/Zend/zend.h
@@ -198,32 +198,15 @@ typedef struct _zend_object {
} zend_object;
typedef unsigned int zend_object_handle;
+typedef struct _zend_object_value zend_object_value;
-typedef struct _zend_object_handlers zend_object_handlers;
+#include "zend_object_handlers.h"
-typedef struct _zend_object_value {
+struct _zend_object_value {
zend_object_handle handle;
zend_object_handlers *handlers;
-} zend_object_value;
-
-typedef zend_object *(*get_address_t)(zend_object_handle handle); /* Don't return zval ** so that we can't change it */
-typedef zval **(*get_property_address_t)(zend_object_handle handle, zval *offset, int type);
-typedef void (*add_ref_t)(zend_object_handle handle);
-typedef void (*del_ref_t)(zend_object_handle handle);
-typedef void (*delete_obj_t)(zend_object_handle handle);
-typedef zend_object_value (*clone_obj_t)(zend_object_handle handle);
-
-struct _zend_object_handlers {
- get_address_t get_address;
- get_property_address_t get_property_address;
- add_ref_t add_ref;
- del_ref_t del_ref;
- delete_obj_t delete_obj;
- clone_obj_t clone_obj;
};
-#include "zend_objects.h"
-
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
@@ -297,6 +280,7 @@ struct _zend_class_entry {
union _zend_function *clone;
/* handlers */
+ zend_object_value (*create_object)(zend_class_entry *class_type);
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
zval (*handle_property_get)(zend_property_reference *property_reference);
int (*handle_property_set)(zend_property_reference *property_reference, zval *value);
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index 3144f31cf2..b1707f595b 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -206,6 +206,11 @@ static int zend_check_class(zval *obj, zend_class_entry *expected_ce)
return 0;
}
+ /* TBI!! new object handlers */
+ if(!IS_ZEND_STD_OBJECT(*obj)) {
+ return 0;
+ }
+
for (ce = Z_OBJCE_P(obj); ce != NULL; ce = ce->parent) {
if (ce == expected_ce) {
return 1;
@@ -577,15 +582,18 @@ ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type
}
arg->type = IS_OBJECT;
- arg->value.obj = zend_objects_new(&object, class_type);
-
- if (properties) {
- object->properties = properties;
+ if(class_type->create_object == NULL) {
+ arg->value.obj = zend_objects_new(&object, class_type);
+ if (properties) {
+ object->properties = properties;
+ } else {
+ ALLOC_HASHTABLE_REL(object->properties);
+ zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+ }
} else {
- ALLOC_HASHTABLE_REL(object->properties);
- zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
- }
+ arg->value.obj = class_type->create_object(class_type);
+ }
return SUCCESS;
}
@@ -1344,7 +1352,7 @@ zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callabl
zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(obj) + 1, (void**)&ce);
efree(lcname);
} else {
- ce = Z_OBJCE_PP(obj);
+ ce = Z_OBJCE_PP(obj); /* ??? */
if (callable_name) {
char *ptr;
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index f13495de83..c78c2fa1db 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -90,6 +90,7 @@
class_container.constructor = NULL; \
class_container.destructor = NULL; \
class_container.clone = NULL; \
+ class_container.create_object = NULL; \
class_container.handle_function_call = NULL; \
class_container.handle_property_get = NULL; \
class_container.handle_property_set = NULL; \
@@ -103,6 +104,7 @@
class_container.constructor = NULL; \
class_container.destructor = NULL; \
class_container.clone = NULL; \
+ class_container.create_object = NULL; \
class_container.handle_function_call = handle_fcall; \
class_container.handle_property_get = handle_propget; \
class_container.handle_property_set = handle_propset; \
@@ -406,7 +408,7 @@ ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length,
#define ZEND_SET_GLOBAL_VAR_WITH_LENGTH(name, name_length, var, _refcount, _is_ref) \
ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), name, name_length, var, _refcount, _is_ref)
-#define HASH_OF(p) ((p)->type==IS_ARRAY ? (p)->value.ht : (((p)->type==IS_OBJECT ? Z_OBJPROP_P(p) : NULL)))
+#define HASH_OF(p) ((p)->type==IS_ARRAY ? (p)->value.ht : (((p)->type==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p) TSRMLS_CC) : NULL)))
#define ZVAL_IS_NULL(z) ((z)->type==IS_NULL)
/* For compatibility */
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index b3c56d751c..da426d51f0 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -491,7 +491,8 @@ ZEND_FUNCTION(defined)
ZEND_FUNCTION(get_class)
{
zval **arg;
- zend_class_entry *ce;
+ char *name;
+ int name_len;
if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &arg)==FAILURE) {
ZEND_WRONG_PARAM_COUNT();
@@ -500,8 +501,12 @@ ZEND_FUNCTION(get_class)
RETURN_FALSE;
}
- ce = Z_OBJCE_PP(arg);
- RETURN_STRINGL(ce->name, ce->name_length, 1);
+ if(Z_OBJ_HT_PP(arg)->get_class_name == NULL ||
+ Z_OBJ_HT_PP(arg)->get_class_name(*arg, &name, &name_len, 0 TSRMLS_CC) != SUCCESS) {
+ RETURN_FALSE;
+ }
+
+ RETURN_STRINGL(name, name_len, 1);
}
/* }}} */
@@ -517,9 +522,16 @@ ZEND_FUNCTION(get_parent_class)
ZEND_WRONG_PARAM_COUNT();
}
- if (Z_TYPE_PP(arg) == IS_OBJECT)
- ce = Z_OBJCE_PP(arg);
- else if (Z_TYPE_PP(arg) == IS_STRING) {
+ if (Z_TYPE_PP(arg) == IS_OBJECT) {
+ char *name;
+ zend_uint name_length;
+
+ if(Z_OBJ_HT_PP(arg)->get_class_name == NULL ||
+ Z_OBJ_HT_PP(arg)->get_class_name(*arg, &name, &name_length, 1 TSRMLS_CC) != SUCCESS) {
+ RETURN_FALSE;
+ }
+ RETURN_STRINGL(name, name_length, 1);
+ } else if (Z_TYPE_PP(arg) == IS_STRING) {
SEPARATE_ZVAL(arg);
zend_str_tolower(Z_STRVAL_PP(arg), Z_STRLEN_PP(arg));
zend_hash_find(EG(class_table), Z_STRVAL_PP(arg), Z_STRLEN_PP(arg)+1, (void **)&ce);
@@ -533,6 +545,7 @@ ZEND_FUNCTION(get_parent_class)
}
/* }}} */
+
static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
{
zval **obj, **class_name;
@@ -546,8 +559,14 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
if (Z_TYPE_PP(obj) != IS_OBJECT) {
RETURN_FALSE;
}
+
+ /* TBI!! new object handlers */
+ if(!IS_ZEND_STD_OBJECT(**obj)) {
+ RETURN_FALSE;
+ }
convert_to_string_ex(class_name);
+
lcname = estrndup(Z_STRVAL_PP(class_name), Z_STRLEN_PP(class_name));
zend_str_tolower(lcname, Z_STRLEN_PP(class_name));
@@ -564,9 +583,10 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
efree(lcname);
RETURN_FALSE;
}
+/* }}} */
/* {{{ proto bool is_subclass_of(object object, string class_name)
- Returns true if the object has this class as one of its parents */
+ Returns true if the object has this class as one of its parents */
ZEND_FUNCTION(is_subclass_of)
{
is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
@@ -630,9 +650,12 @@ ZEND_FUNCTION(get_object_vars)
if ((*obj)->type != IS_OBJECT) {
RETURN_FALSE;
}
+ if(Z_OBJ_HT_PP(obj)->get_properties == NULL) {
+ RETURN_FALSE;
+ }
array_init(return_value);
- zend_hash_copy(return_value->value.ht, Z_OBJPROP_PP(obj),
+ zend_hash_copy(return_value->value.ht, Z_OBJ_HT_PP(obj)->get_properties(*obj TSRMLS_CC),
(copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
}
/* }}} */
@@ -653,9 +676,13 @@ ZEND_FUNCTION(get_class_methods)
ZEND_WRONG_PARAM_COUNT();
}
- if (Z_TYPE_PP(class) == IS_OBJECT)
+ if (Z_TYPE_PP(class) == IS_OBJECT) {
+ /* TBI!! new object handlers */
+ if(!IS_ZEND_STD_OBJECT(**class)) {
+ RETURN_FALSE;
+ }
ce = Z_OBJCE_PP(class);
- else if (Z_TYPE_PP(class) == IS_STRING) {
+ } else if (Z_TYPE_PP(class) == IS_STRING) {
SEPARATE_ZVAL(class);
zend_str_tolower(Z_STRVAL_PP(class), Z_STRLEN_PP(class));
zend_hash_find(EG(class_table), Z_STRVAL_PP(class), Z_STRLEN_PP(class)+1, (void **)&ce);
@@ -692,6 +719,12 @@ ZEND_FUNCTION(method_exists)
if ((*klass)->type != IS_OBJECT) {
RETURN_FALSE;
}
+
+ /* TBI!! new object handlers */
+ if(!IS_ZEND_STD_OBJECT(**klass)) {
+ RETURN_FALSE;
+ }
+
convert_to_string_ex(method_name);
lcname = estrndup((*method_name)->value.str.val, (*method_name)->value.str.len);
zend_str_tolower(lcname, (*method_name)->value.str.len);
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index ba164c8969..b4010ea1a4 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1373,13 +1373,14 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
new_class_entry.destructor = NULL;
new_class_entry.clone = NULL;
+ new_class_entry.create_object = NULL;
new_class_entry.handle_function_call = NULL;
new_class_entry.handle_property_set = NULL;
new_class_entry.handle_property_get = NULL;
new_class_entry.parent = NULL;
- if (zend_hash_update(class_table, new_class_entry.name, name_length+1, &new_class_entry, sizeof(zend_class_entry), ce) == FAILURE) {
+ if (zend_hash_update(class_table, new_class_entry.name, name_length+1, &new_class_entry, sizeof(zend_class_entry), (void **)ce) == FAILURE) {
zend_error(E_ERROR, "Can't create class. Fatal error, please report!");
}
}
@@ -1396,7 +1397,7 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en
cur = tsrm_strtok_r(path, ":", &temp);
- if (zend_hash_find(class_table, cur, strlen(cur)+1, &ce) == FAILURE) {
+ if (zend_hash_find(class_table, cur, strlen(cur)+1, (void **)&ce) == FAILURE) {
create_class(class_table, cur, strlen(cur), &ce);
}
@@ -1407,7 +1408,7 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en
if (!cur) {
break;
}
- if (zend_hash_find(&ce->class_table, last, strlen(last)+1, &ce) == FAILURE) {
+ if (zend_hash_find(&ce->class_table, last, strlen(last)+1, (void **)&ce) == FAILURE) {
create_class(&ce->class_table, last, strlen(last), &ce);
}
last = cur;
@@ -1862,6 +1863,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
new_class_entry.destructor = NULL;
new_class_entry.clone = NULL;
+ new_class_entry.create_object = NULL;
new_class_entry.handle_function_call = NULL;
new_class_entry.handle_property_set = NULL;
new_class_entry.handle_property_get = NULL;
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 4873d95397..f2c704f9e3 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -54,9 +54,6 @@
/* Prototypes */
-static zval get_overloaded_property(temp_variable *T TSRMLS_DC);
-static void set_overloaded_property(temp_variable *T, zval *value TSRMLS_DC);
-static void call_overloaded_function(temp_variable *T, int arg_count, zval *return_value TSRMLS_DC);
static void zend_fetch_var_address(zend_op *opline, temp_variable *Ts, int type TSRMLS_DC);
static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC);
static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC);
@@ -87,12 +84,6 @@ static inline zval *_get_zval_ptr(znode *node, temp_variable *Ts, int *should_fr
*should_free = 1;
switch (Ts[node->u.var].EA.type) {
- case IS_OVERLOADED_OBJECT:
- Ts[node->u.var].tmp_var = get_overloaded_property(&Ts[node->u.var] TSRMLS_CC);
- Ts[node->u.var].tmp_var.refcount=1;
- Ts[node->u.var].tmp_var.is_ref=1;
- return &Ts[node->u.var].tmp_var;
- break;
case IS_STRING_OFFSET: {
temp_variable *T = &Ts[node->u.var];
zval *str = T->EA.data.str_offset.str;
@@ -171,8 +162,7 @@ static inline zval **_get_zval_ptr_ptr(znode *node, temp_variable *Ts TSRMLS_DC)
}
}
-
-static inline zval **zend_fetch_property_address_inner(HashTable *ht, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
+static inline zval **zend_fetch_property_address_inner(zval *object, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
{
zval *prop_ptr = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R);
zval **retval;
@@ -194,28 +184,8 @@ static inline zval **zend_fetch_property_address_inner(HashTable *ht, znode *op2
break;
}
- if (zend_hash_find(ht, prop_ptr->value.str.val, prop_ptr->value.str.len+1, (void **) &retval) == FAILURE) {
- switch (type) {
- case BP_VAR_R:
- zend_error(E_NOTICE,"Undefined property: %s", prop_ptr->value.str.val);
- /* break missing intentionally */
- case BP_VAR_IS:
- retval = &EG(uninitialized_zval_ptr);
- break;
- case BP_VAR_RW:
- zend_error(E_NOTICE,"Undefined property: %s", prop_ptr->value.str.val);
- /* break missing intentionally */
- case BP_VAR_W: {
- zval *new_zval = &EG(uninitialized_zval);
-
- new_zval->refcount++;
- zend_hash_update(ht, prop_ptr->value.str.val, prop_ptr->value.str.len+1, &new_zval, sizeof(zval *), (void **) &retval);
- }
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
-
+ retval = Z_OBJ_HT_P(object)->get_property_ptr(object, prop_ptr TSRMLS_CC);
+
if (prop_ptr == &tmp) {
zval_dtor(prop_ptr);
}
@@ -306,32 +276,6 @@ static inline void zend_assign_to_variable(znode *result, znode *op1, znode *op2
if (!variable_ptr_ptr) {
switch (Ts[op1->u.var].EA.type) {
- case IS_OVERLOADED_OBJECT:
- {
- int return_value_used;
-
- return_value_used = result && !(result->u.EA.type & EXT_TYPE_UNUSED);
-
- if (return_value_used) {
- if (type == IS_TMP_VAR) {
- MAKE_STD_ZVAL(*Ts[result->u.var].var.ptr_ptr);
- **Ts[result->u.var].var.ptr_ptr = *value;
- INIT_PZVAL(*Ts[result->u.var].var.ptr_ptr);
- } else {
- Ts[result->u.var].var.ptr_ptr = &value;
- PZVAL_LOCK(*Ts[result->u.var].var.ptr_ptr);
- }
- AI_USE_PTR(Ts[result->u.var].var);
- }
-
- set_overloaded_property(&Ts[op1->u.var], value TSRMLS_CC);
-
- if (!return_value_used && type == IS_TMP_VAR) {
- zval_dtor(value);
- }
- return;
- break;
- }
case IS_STRING_OFFSET: {
temp_variable *T = &Ts[op1->u.var];
@@ -528,11 +472,11 @@ static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_vari
return EG(active_symbol_table);
break;
case ZEND_FETCH_GLOBAL:
-/* Don't think this is actually needed.
- if (opline->op1.op_type == IS_VAR) {
+ /* Don't think this is actually needed.
+ if (opline->op1.op_type == IS_VAR) {
PZVAL_LOCK(varname);
}
-*/
++ */
return &EG(symbol_table);
break;
case ZEND_FETCH_STATIC:
@@ -549,6 +493,7 @@ static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_vari
if (!EG(this)) {
zend_error(E_ERROR, "Using $this when not in object context");
}
+ /* HACK!! 'this' should be always zend_object */
return Z_OBJPROP_P(EG(this));
break;
case ZEND_FETCH_THIS:
@@ -569,6 +514,7 @@ static inline HashTable *zend_get_target_symbol_table(zend_op *opline, temp_vari
}
EMPTY_SWITCH_DEFAULT_CASE()
}
+ return NULL;
}
@@ -711,54 +657,12 @@ fetch_string_dim:
return retval;
}
-static void fetch_overloaded_element(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type, zval ***retval, int overloaded_element_type TSRMLS_DC)
-{
- zend_overloaded_element overloaded_element;
-
- if (Ts[op1->u.var].EA.type == IS_STRING_OFFSET) {
- get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R);
- switch (type) {
- case BP_VAR_R:
- case BP_VAR_IS:
- *retval = &EG(uninitialized_zval_ptr);
- break;
- case BP_VAR_W:
- case BP_VAR_RW:
- *retval = &EG(error_zval_ptr);
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- SELECTIVE_PZVAL_LOCK(**retval, result);
- return;
- }
-
- overloaded_element.element = *get_zval_ptr(op2, Ts, &EG(free_op2), type);
- overloaded_element.type = overloaded_element_type;
- if (!EG(free_op2)) {
- zval_copy_ctor(&overloaded_element.element);
- }
-
- Ts[result->u.var].EA = Ts[op1->u.var].EA;
- zend_llist_add_element(Ts[result->u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
-
- Ts[result->u.var].EA.type = IS_OVERLOADED_OBJECT;
- *retval = NULL;
- return;
-}
-
-
static void zend_fetch_dimension_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
{
zval **container_ptr = get_zval_ptr_ptr(op1, Ts, type);
zval *container;
zval ***retval = &Ts[result->u.var].var.ptr_ptr;
-
- if (container_ptr == NULL) {
- fetch_overloaded_element(result, op1, op2, Ts, type, retval, OE_IS_ARRAY TSRMLS_CC);
- return;
- }
-
container = *container_ptr;
if (container == EG(error_zval_ptr)) {
@@ -872,50 +776,22 @@ static void zend_fetch_dimension_address_from_tmp_var(znode *result, znode *op1,
SELECTIVE_PZVAL_LOCK(*Ts[result->u.var].var.ptr_ptr, result);
}
-
static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
{
zval **container_ptr = get_zval_ptr_ptr(op1, Ts, type);
zval *container;
zval ***retval = &Ts[result->u.var].var.ptr_ptr;
-
-
- if (container_ptr == NULL) {
- fetch_overloaded_element(result, op1, op2, Ts, type, retval, OE_IS_OBJECT TSRMLS_CC);
- return;
- }
-
+
container = *container_ptr;
if (container == EG(error_zval_ptr)) {
*retval = &EG(error_zval_ptr);
SELECTIVE_PZVAL_LOCK(**retval, result);
return;
}
-
- if (container->type == IS_OBJECT &&
- ((type == BP_VAR_W && Z_OBJCE_P(container)->handle_property_set) ||
- (type != BP_VAR_W && Z_OBJCE_P(container)->handle_property_get))) {
- zend_overloaded_element overloaded_element;
-
- Ts[result->u.var].EA.data.overloaded_element.object = container;
- Ts[result->u.var].EA.data.overloaded_element.type = type;
- Ts[result->u.var].EA.data.overloaded_element.elements_list = (zend_llist *) emalloc(sizeof(zend_llist));
- zend_llist_init(Ts[result->u.var].EA.data.overloaded_element.elements_list, sizeof(zend_overloaded_element), NULL, 0);
- overloaded_element.element = *get_zval_ptr(op2, Ts, &EG(free_op2), type);
- overloaded_element.type = OE_IS_OBJECT;
- if (!EG(free_op2)) {
- zval_copy_ctor(&overloaded_element.element);
- }
- zend_llist_add_element(Ts[result->u.var].EA.data.overloaded_element.elements_list, &overloaded_element);
- Ts[result->u.var].EA.type = IS_OVERLOADED_OBJECT;
- *retval = NULL;
- return;
- }
-
-
- if (container->type==IS_NULL
- || (container->type==IS_BOOL && container->value.lval==0)
- || (container->type==IS_STRING && container->value.str.len==0)) {
+
+ if (container->type == IS_NULL
+ || (container->type == IS_BOOL && container->value.lval==0)
+ || (container->type == IS_STRING && container->value.str.len == 0)) {
switch (type) {
case BP_VAR_RW:
case BP_VAR_W:
@@ -927,13 +803,13 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
break;
}
}
-
+
if (container->type != IS_OBJECT) {
zval *offset;
-
+
offset = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R);
FREE_OP(Ts, op2, EG(free_op2));
- if (type==BP_VAR_R || type==BP_VAR_IS) {
+ if (type == BP_VAR_R || type == BP_VAR_IS) {
*retval = &EG(uninitialized_zval_ptr);
} else {
*retval = &EG(error_zval_ptr);
@@ -941,56 +817,71 @@ static void zend_fetch_property_address(znode *result, znode *op1, znode *op2, t
SELECTIVE_PZVAL_LOCK(**retval, result);
return;
}
-
-
+
+
if ((type==BP_VAR_W || type==BP_VAR_RW) && container->refcount>1 && !PZVAL_IS_REF(container)) {
SEPARATE_ZVAL(container_ptr);
container = *container_ptr;
}
- *retval = zend_fetch_property_address_inner(Z_OBJPROP_P(container), op2, Ts, type TSRMLS_CC);
+ *retval = zend_fetch_property_address_inner(container, op2, Ts, type TSRMLS_CC);
SELECTIVE_PZVAL_LOCK(**retval, result);
}
-
-static zval get_overloaded_property(temp_variable *T TSRMLS_DC)
+static void zend_fetch_property_address_read(znode *result, znode *op1, znode *op2, temp_variable *Ts, int type TSRMLS_DC)
{
- zval result;
-
- result = Z_OBJCE_P(T->EA.data.overloaded_element.object)->handle_property_get(&T->EA.data.overloaded_element);
-
- zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
- efree(T->EA.data.overloaded_element.elements_list);
- return result;
-}
+ zval *container;
+ zval **retval;
+ retval = &Ts[result->u.var].var.ptr;
+ Ts[result->u.var].var.ptr_ptr = retval;
-static void set_overloaded_property(temp_variable *T, zval *value TSRMLS_DC)
-{
- zend_class_entry *ce;
+ container = get_zval_ptr(op1, Ts, &EG(free_op1), type);
- ce = Z_OBJCE_P(T->EA.data.overloaded_element.object);
- if (ce->handle_property_set) {
- ce->handle_property_set(&T->EA.data.overloaded_element, value);
- } else {
- zend_error(E_ERROR, "Class '%s' does not support setting overloaded properties", ce->name);
+ if (container == EG(error_zval_ptr)) {
+ *retval = EG(error_zval_ptr);
+ SELECTIVE_PZVAL_LOCK(*retval, result);
+ return;
}
- zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
- efree(T->EA.data.overloaded_element.elements_list);
-}
+
+ if(container->type != IS_OBJECT) {
+ zend_error(E_NOTICE, "Trying to get property of non-object");
-static void call_overloaded_function(temp_variable *T, int arg_count, zval *return_value TSRMLS_DC)
-{
- zend_class_entry *ce;
-
- ce = Z_OBJCE_P(T->EA.data.overloaded_element.object);
- if (ce->handle_function_call) {
- ce->handle_function_call(arg_count, return_value, T->EA.data.overloaded_element.object, 1 TSRMLS_CC, &T->EA.data.overloaded_element);
+ if (type==BP_VAR_R || type==BP_VAR_IS) {
+ *retval = EG(uninitialized_zval_ptr);
+ } else {
+ *retval = EG(error_zval_ptr);
+ }
} else {
- zend_error(E_ERROR, "Class '%s' does not support overloaded method calls", ce->name);
+ zval *offset;
+ zval tmp;
+
+ offset = get_zval_ptr(op2, Ts, &EG(free_op2), BP_VAR_R);
+ switch (op2->op_type) {
+ case IS_CONST:
+ /* already a constant string */
+ break;
+ case IS_VAR:
+ tmp = *offset;
+ zval_copy_ctor(&tmp);
+ convert_to_string(&tmp);
+ offset = &tmp;
+ break;
+ case IS_TMP_VAR:
+ convert_to_string(offset);
+ break;
+ }
+
+ /* here we are sure we are dealing with an object */
+ *retval = Z_OBJ_HT_P(container)->read_property(container, offset, type TSRMLS_CC);
+ if (offset == &tmp) {
+ zval_dtor(offset);
+ }
+ FREE_OP(Ts, op2, EG(free_op2));
}
- zend_llist_destroy(T->EA.data.overloaded_element.elements_list);
- efree(T->EA.data.overloaded_element.elements_list);
+
+ SELECTIVE_PZVAL_LOCK(*retval, result);
+ return;
}
@@ -1009,6 +900,8 @@ static int zend_check_symbol(zval **pz TSRMLS_DC)
} else if (Z_TYPE_PP(pz) == IS_ARRAY) {
zend_hash_apply(Z_ARRVAL_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
} else if (Z_TYPE_PP(pz) == IS_OBJECT) {
+
+ /* OBJ-TBI - doesn't support new object model! */
zend_hash_apply(Z_OBJPROP_PP(pz), (apply_func_t) zend_check_symbol TSRMLS_CC);
}
@@ -1038,6 +931,7 @@ typedef struct _zend_execute_data {
zend_op *opline;
zend_function_state function_state;
zend_function *fbc; /* Function Being Called */
+ zend_function *fbc_constructor;
object_info object;
temp_variable *Ts;
zend_bool original_in_execution;
@@ -1332,7 +1226,7 @@ binary_assign_op_addr: {
PZVAL_LOCK(*EX(Ts)[EX(opline)->result.u.var].var.ptr_ptr);
NEXT_OPCODE();
case ZEND_FETCH_OBJ_R:
- zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
+ zend_fetch_property_address_read(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
AI_USE_PTR(EX(Ts)[EX(opline)->result.u.var].var);
NEXT_OPCODE();
case ZEND_FETCH_OBJ_W:
@@ -1342,7 +1236,7 @@ binary_assign_op_addr: {
zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_RW TSRMLS_CC);
NEXT_OPCODE();
case ZEND_FETCH_OBJ_IS:
- zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_IS TSRMLS_CC);
+ zend_fetch_property_address_read(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_IS TSRMLS_CC);
AI_USE_PTR(EX(Ts)[EX(opline)->result.u.var].var);
NEXT_OPCODE();
case ZEND_FETCH_OBJ_FUNC_ARG:
@@ -1350,7 +1244,7 @@ binary_assign_op_addr: {
/* Behave like FETCH_OBJ_W */
zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_W TSRMLS_CC);
} else {
- zend_fetch_property_address(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
+ zend_fetch_property_address_read(&EX(opline)->result, &EX(opline)->op1, &EX(opline)->op2, EX(Ts), BP_VAR_R TSRMLS_CC);
AI_USE_PTR(EX(Ts)[EX(opline)->result.u.var].var);
}
NEXT_OPCODE();
@@ -1589,20 +1483,24 @@ binary_assign_op_addr: {
zval_copy_ctor(this_ptr);
EX(object).ptr = this_ptr;
}
- EX(fbc) = Z_OBJCE_P(EX(object).ptr)->constructor;
- EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr);
+
+ EX(fbc) = EX(fbc_constructor);
+ if(EX(fbc)->type == ZEND_USER_FUNCTION) { /* HACK!! */
+ EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr);
+ } else {
+ EX(calling_namespace) = NULL;
+ }
+
NEXT_OPCODE();
}
case ZEND_INIT_METHOD_CALL:
{
zval *function_name;
- zend_function *function;
- HashTable *active_function_table;
zval tmp;
zend_bool is_const;
char *function_name_strval;
int function_name_strlen;
-
+
zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr);
is_const = (EX(opline)->op2.op_type == IS_CONST);
@@ -1634,13 +1532,15 @@ binary_assign_op_addr: {
EX(object).ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
}
- /* Nuked overloaded method code. This will be redone differently */
-
if (EX(object).ptr && EX(object).ptr->type == IS_OBJECT) {
- active_function_table = &Z_OBJCE_P(EX(object).ptr)->function_table;
+ EX(fbc) = Z_OBJ_HT_P(EX(object).ptr)->get_method(EX(object).ptr, function_name_strval, function_name_strlen TSRMLS_CC);
} else {
zend_error(E_ERROR, "Call to a member function on a non-object");
}
+ if (!EX(fbc)) {
+ zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
+ }
+
if (!PZVAL_IS_REF(EX(object).ptr)) {
EX(object).ptr->refcount++; /* For $this pointer */
} else {
@@ -1652,18 +1552,17 @@ binary_assign_op_addr: {
EX(object).ptr = this_ptr;
}
- EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr);
-
- if (zend_hash_find(active_function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) {
- zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval);
+ if(EX(fbc)->type == ZEND_USER_FUNCTION) {
+ EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr);
+ } else {
+ EX(calling_namespace) = NULL;
}
if (!is_const) {
zval_dtor(&tmp);
FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2));
}
-
- EX(fbc) = function;
+
NEXT_OPCODE();
}
case ZEND_INIT_STATIC_METHOD_CALL:
@@ -1697,7 +1596,7 @@ binary_assign_op_addr: {
EX(calling_namespace) = EG(namespace);
- if (EX(object).ptr = EG(this)) {
+ if ((EX(object).ptr = EG(this))) {
EX(object).ptr->refcount++;
}
@@ -1751,7 +1650,7 @@ binary_assign_op_addr: {
do {
if (EG(namespace)) {
if (zend_hash_find(&EG(namespace)->function_table, function_name_strval, function_name_strlen+1, (void **) &function) == SUCCESS) {
- if (EX(object).ptr = EG(this)) {
+ if ((EX(object).ptr = EG(this))) {
EX(object).ptr->refcount++;
}
break;
@@ -1783,7 +1682,7 @@ binary_assign_op_addr: {
do {
if (EG(namespace)) {
if (zend_hash_find(&EG(namespace)->function_table, fname->value.str.val, fname->value.str.len+1, (void **) &EX(function_state).function) == SUCCESS) {
- if (EX(object).ptr = EG(this)) {
+ if ((EX(object).ptr = EG(this))) {
EX(object).ptr->refcount++;
}
break;
@@ -1868,7 +1767,13 @@ do_fcall_common:
} else { /* ZEND_OVERLOADED_FUNCTION */
ALLOC_ZVAL(EX(Ts)[EX(opline)->result.u.var].var.ptr);
INIT_ZVAL(*(EX(Ts)[EX(opline)->result.u.var].var.ptr));
- call_overloaded_function(&EX(Ts)[EX(fbc)->overloaded_function.var], EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr TSRMLS_CC);
+
+ if(EX(object).ptr) {
+ Z_OBJ_HT_P(EX(object).ptr)->call_method(EX(fbc)->common.function_name, EX(opline)->extended_value, EX(Ts)[EX(opline)->result.u.var].var.ptr, EX(object).ptr, return_value_used TSRMLS_CC);
+ } else {
+ zend_error(E_ERROR, "Cannot call overloaded function for non-object");
+ }
+
efree(EX(fbc));
if (!return_value_used) {
zval_ptr_dtor(&EX(Ts)[EX(opline)->result.u.var].var.ptr);
@@ -2236,7 +2141,7 @@ send_by_ref:
EX(Ts)[EX(opline)->result.u.var].var.ptr_ptr = &EX(Ts)[EX(opline)->result.u.var].var.ptr;
ALLOC_ZVAL(EX(Ts)[EX(opline)->result.u.var].var.ptr);
- EX(Ts)[EX(opline)->result.u.var].var.ptr->value.obj = obj->value.obj.handlers->clone_obj(obj->value.obj.handle);
+ EX(Ts)[EX(opline)->result.u.var].var.ptr->value.obj = Z_OBJ_HT_P(obj)->clone_obj(obj);
EX(Ts)[EX(opline)->result.u.var].var.ptr->type = IS_OBJECT;
EX(Ts)[EX(opline)->result.u.var].var.ptr->refcount=1;
EX(Ts)[EX(opline)->result.u.var].var.ptr->is_ref=1;
@@ -2500,10 +2405,6 @@ send_by_ref:
zval tmp, *variable = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
zval **object;
zend_bool unset_object;
- HashTable *target_symbol_table;
-
- target_symbol_table = zend_get_target_symbol_table(EX(opline), EX(Ts), BP_VAR_IS TSRMLS_CC);
- /* Need to handle target_symbol_table == NULL */
if (variable->type != IS_STRING) {
tmp = *variable;
@@ -2515,16 +2416,16 @@ send_by_ref:
unset_object = (EX(opline)->extended_value == ZEND_UNSET_OBJ);
if (unset_object) {
- if (zend_hash_find(target_symbol_table, variable->value.str.val, variable->value.str.len+1, (void **)&object) == FAILURE) {
+ if (zend_hash_find(EG(active_symbol_table), variable->value.str.val, variable->value.str.len+1, (void **)&object) == FAILURE) {
zend_error(E_ERROR, "Cannot delete non-existing object");
}
if (Z_TYPE_PP(object) != IS_OBJECT) {
zend_error(E_ERROR, "Cannot call delete on non-object type");
}
- (*object)->value.obj.handlers->delete_obj((*object)->value.obj.handle);
+ Z_OBJ_HT_PP(object)->delete_obj((*object));
}
- zend_hash_del(target_symbol_table, variable->value.str.val, variable->value.str.len+1);
+ zend_hash_del(EG(active_symbol_table), variable->value.str.val, variable->value.str.len+1);
if (variable == &tmp) {
zval_dtor(&tmp);
@@ -2543,16 +2444,13 @@ send_by_ref:
if (container) {
HashTable *ht;
- switch ((*container)->type) {
- case IS_ARRAY:
- ht = (*container)->value.ht;
- break;
- case IS_OBJECT:
- ht = Z_OBJPROP_PP(container);
- break;
- default:
- ht = NULL;
- break;
+ if((*container)->type == IS_ARRAY) {
+ ht = (*container)->value.ht;
+ } else {
+ ht = NULL;
+ if((*container)->type == IS_OBJECT) {
+ Z_OBJ_HT_P(*container)->unset_property(*container, offset TSRMLS_CC);
+ }
}
if (ht) {
switch (offset->type) {
@@ -2576,7 +2474,7 @@ send_by_ref:
if (Z_TYPE_PP(object) != IS_OBJECT) {
zend_error(E_ERROR, "Cannot call delete on non-object type");
}
- (*object)->value.obj.handlers->delete_obj((*object)->value.obj.handle);
+ Z_OBJ_HT_PP(object)->delete_obj(*object);
}
zend_hash_index_del(ht, index);
@@ -2590,7 +2488,7 @@ send_by_ref:
if (Z_TYPE_PP(object) != IS_OBJECT) {
zend_error(E_ERROR, "Cannot call delete on non-object type");
}
- (*object)->value.obj.handlers->delete_obj((*object)->value.obj.handle);
+ Z_OBJ_HT_PP(object)->delete_obj(*object);
}
zend_hash_del(ht, offset->value.str.val, offset->value.str.len+1);
@@ -2603,7 +2501,7 @@ send_by_ref:
if (Z_TYPE_PP(object) != IS_OBJECT) {
zend_error(E_ERROR, "Cannot call delete on non-object type");
}
- (*object)->value.obj.handlers->delete_obj((*object)->value.obj.handle);
+ Z_OBJ_HT_PP(object)->delete_obj(*object);
}
zend_hash_del(ht, "", sizeof(""));
@@ -2702,19 +2600,23 @@ send_by_ref:
NEXT_OPCODE();
case ZEND_JMP_NO_CTOR: {
zval *object_zval;
- zend_object *object;
+ zend_function *constructor;
if (EX(opline)->op1.op_type == IS_VAR) {
PZVAL_LOCK(*EX(Ts)[EX(opline)->op1.u.var].var.ptr_ptr);
}
object_zval = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R);
- object = object_zval->value.obj.handlers->get_address(object_zval->value.obj.handle);
+ constructor = Z_OBJ_HT_P(object_zval)->get_constructor(object_zval TSRMLS_CC);
- if (!object->ce->handle_function_call && !object->ce->constructor) {
+ EX(fbc_constructor) = NULL;
+ if (constructor == NULL) {
EX(opline) = op_array->opcodes + EX(opline)->op2.u.opline_num;
continue;
+ } else {
+ EX(fbc_constructor) = constructor;
}
+
}
NEXT_OPCODE();
case ZEND_ISSET_ISEMPTY_VAR:
@@ -2725,7 +2627,6 @@ send_by_ref:
HashTable *target_symbol_table;
target_symbol_table = zend_get_target_symbol_table(EX(opline), EX(Ts), BP_VAR_IS TSRMLS_CC);
- /* Need to handle target_symbol_table == NULL */
if (variable->type != IS_STRING) {
tmp = *variable;
@@ -2767,24 +2668,17 @@ send_by_ref:
{
zval **container = get_zval_ptr_ptr(&EX(opline)->op1, EX(Ts), BP_VAR_R);
zval *offset = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R);
- zval **value;
- int isset = 1;
+ zval **value = NULL;
+ int result = 0;
if (container) {
- HashTable *ht;
- switch ((*container)->type) {
- case IS_ARRAY:
- ht = (*container)->value.ht;
- break;
- case IS_OBJECT:
- ht = Z_OBJPROP_PP(container);
- break;
- default:
- ht = NULL;
- break;
- }
- if (ht) {
+ if((*container)->type == IS_ARRAY) {
+ HashTable *ht;
+ int isset = 0;
+
+ ht = (*container)->value.ht;
+
switch (offset->type) {
case IS_DOUBLE:
case IS_RESOURCE:
@@ -2798,46 +2692,60 @@ send_by_ref:
} else {
index = offset->value.lval;
}
- if (zend_hash_index_find(ht, index, (void **) &value) == FAILURE) {
- isset = 0;
+ if (zend_hash_index_find(ht, index, (void **) &value) == SUCCESS) {
+ isset = 1;
}
break;
}
case IS_STRING:
- if (zend_hash_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == FAILURE) {
- isset = 0;
+ if (zend_hash_find(ht, offset->value.str.val, offset->value.str.len+1, (void **) &value) == SUCCESS) {
+ isset = 1;
}
break;
case IS_NULL:
- if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == FAILURE) {
- isset = 0;
+ if (zend_hash_find(ht, "", sizeof(""), (void **) &value) == SUCCESS) {
+ isset = 1;
}
break;
default:
zend_error(E_WARNING, "Illegal offset type in unset");
+
break;
}
+
+ switch (EX(opline)->extended_value) {
+ case ZEND_ISSET:
+ if (isset && Z_TYPE_PP(value) == IS_NULL) {
+ result = 0;
+ } else {
+ result = isset;
+ }
+ break;
+ case ZEND_ISEMPTY:
+ if (!isset || !zend_is_true(*value)) {
+ result = 0;
+ } else {
+ result = 1;
+ }
+ break;
+ }
+ } else {
+ if((*container)->type == IS_OBJECT) {
+ result = Z_OBJ_HT_P(*container)->has_property(*container, offset, (EX(opline)->extended_value == ZEND_ISEMPTY) TSRMLS_CC);
+ }
}
} else {
- /* overloaded element & string offsets */
+ /* string offsets */
}
EX(Ts)[EX(opline)->result.u.var].tmp_var.type = IS_BOOL;
switch (EX(opline)->extended_value) {
case ZEND_ISSET:
- if (isset && Z_TYPE_PP(value) == IS_NULL) {
- EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0;
- } else {
- EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = isset;
- }
+ EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = result;
break;
case ZEND_ISEMPTY:
- if (!isset || !zend_is_true(*value)) {
- EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 1;
- } else {
- EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = 0;
- }
+ EX(Ts)[EX(opline)->result.u.var].tmp_var.value.lval = !result;
break;
}
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index e5d90d469c..f4ee73dbf6 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -65,6 +65,7 @@ static inline void safe_free_zval_ptr(zval *p)
}
ZEND_API int zend_eval_string(char *str, zval *retval_ptr, char *string_name TSRMLS_DC);
+
static inline int i_zend_is_true(zval *op)
{
int result;
@@ -93,7 +94,8 @@ static inline int i_zend_is_true(zval *op)
result = (zend_hash_num_elements(op->value.ht)?1:0);
break;
case IS_OBJECT:
- result = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
+ /* OBJ-TBI */
+ result = 1;
break;
default:
result = 0;
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index e116a5ca03..4e324d2eec 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -331,7 +331,7 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC)
last = tsrm_strtok_r(p->value.str.val, ":", &temp);
- if (zend_hash_find(EG(class_table), last, strlen(last)+1, &ce) == FAILURE) {
+ if (zend_hash_find(EG(class_table), last, strlen(last)+1, (void **)&ce) == FAILURE) {
zend_error(E_ERROR, "Invalid class! Improve this error message");
}
@@ -342,7 +342,7 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC)
if (!cur) {
break;
}
- if (zend_hash_find(&ce->class_table, last, strlen(last)+1, &ce) == FAILURE) {
+ if (zend_hash_find(&ce->class_table, last, strlen(last)+1, (void **)&ce) == FAILURE) {
zend_error(E_ERROR, "Invalid class! Improve this error message");
}
last = cur;
@@ -477,7 +477,14 @@ int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *fun
if (object_pp && !*object_pp) {
object_pp = NULL;
}
+
if (object_pp) {
+ /* TBI!! new object handlers */
+ if(!IS_ZEND_STD_OBJECT(**object_pp)) {
+ zend_error(E_WARNING, "Cannot use call_user_function on overloaded objects");
+ return FAILURE;
+ }
+
if (Z_TYPE_PP(object_pp) == IS_OBJECT) {
function_table = &Z_OBJCE_PP(object_pp)->function_table;
calling_namespace = Z_OBJCE_PP(object_pp);
diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h
index 2ac149e47b..3e5dbab7c2 100644
--- a/Zend/zend_globals.h
+++ b/Zend/zend_globals.h
@@ -31,6 +31,7 @@
#include "zend_hash.h"
#include "zend_llist.h"
#include "zend_fast_cache.h"
+#include "zend_objects.h"
/* Define ZTS if you want a thread-safe Zend */
/*#undef ZTS*/
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
new file mode 100644
index 0000000000..44d2526326
--- /dev/null
+++ b/Zend/zend_object_handlers.c
@@ -0,0 +1,257 @@
+#include "zend.h"
+#include "zend_globals.h"
+#include "zend_variables.h"
+#include "zend_API.h"
+#include "zend_objects.h"
+#include "zend_object_handlers.h"
+
+#define DEBUG_OBJECT_HANDLERS 1
+
+static HashTable *zend_std_get_properties(zval *object TSRMLS_DC)
+{
+ zend_object *zobj;
+ zobj = Z_GET_OBJ(object);
+ return zobj->properties;
+}
+
+zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
+{
+ zend_object *zobj;
+ zval tmp_member;
+ zval **retval;
+
+ zobj = Z_GET_OBJ(object);
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+
+#if DEBUG_OBJECT_HANDLERS
+ fprintf(stderr, "Read object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
+#endif
+
+ if (zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &retval) == FAILURE) {
+ switch (type) {
+ case BP_VAR_R:
+ zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member));
+ /* break missing intentionally */
+ case BP_VAR_IS:
+ retval = &EG(uninitialized_zval_ptr);
+ break;
+ case BP_VAR_RW:
+ zend_error(E_NOTICE,"Undefined property: %s", Z_STRVAL_P(member));
+ /* break missing intentionally */
+ case BP_VAR_W: {
+ zval *new_zval = &EG(uninitialized_zval);
+
+ new_zval->refcount++;
+ zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &new_zval, sizeof(zval *), (void **) &retval);
+ }
+ break;
+ EMPTY_SWITCH_DEFAULT_CASE()
+
+ }
+ }
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+ return *retval;
+}
+
+static void zend_std_write_property(zval *object, zval *member, zval *value TSRMLS_DC)
+{
+ zend_object *zobj;
+ zval tmp_member;
+ zval *variable_ptr;
+
+ zobj = Z_GET_OBJ(object);
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+
+ if (zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member), (void **) &variable_ptr) == SUCCESS) {
+ if (variable_ptr == EG(error_zval_ptr) || member == EG(error_zval_ptr)) {
+ /* variable_ptr = EG(uninitialized_zval_ptr); */
+/* } else if (variable_ptr==&EG(uninitialized_zval) || variable_ptr!=value_ptr) { */
+ } else if (variable_ptr != value) {
+ variable_ptr->refcount--;
+ if (variable_ptr->refcount == 0) {
+ zendi_zval_dtor(*variable_ptr);
+ FREE_ZVAL(variable_ptr);
+ }
+ }
+ }
+
+ zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &value, sizeof(zval *), NULL);
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+}
+
+static zval **zend_std_get_property_ptr(zval *object, zval *member TSRMLS_DC)
+{
+ zend_object *zobj;
+ zval tmp_member;
+ zval **retval;
+
+ zobj = Z_GET_OBJ(object);
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+
+#if DEBUG_OBJECT_HANDLERS
+ fprintf(stderr, "Ptr object #%d property: %s\n", Z_OBJ_HANDLE_P(object), Z_STRVAL_P(member));
+#endif
+
+ if (zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **) &retval) == FAILURE) {
+ zval *new_zval = &EG(uninitialized_zval);
+
+ // zend_error(E_NOTICE, "Undefined property: %s", Z_STRVAL_P(member));
+ new_zval->refcount++;
+ zend_hash_update(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, &new_zval, sizeof(zval *), (void **) &retval);
+ }
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+ return retval;
+}
+
+static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
+{
+ zend_object *zobj;
+ zval tmp_member;
+
+ zobj = Z_GET_OBJ(object);
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+ zend_hash_del(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1);
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+}
+
+static union _zend_function *zend_std_get_method(zval *object, char *method_name, int method_len TSRMLS_DC)
+{
+ zend_object *zobj;
+ zend_function *func_method;
+
+ zobj = Z_GET_OBJ(object);
+ if(zend_hash_find(&zobj->ce->function_table, method_name, method_len+1, (void **)&func_method) == FAILURE) {
+ zend_error(E_ERROR, "Call to undefined function %s()", method_name);
+ }
+
+ return func_method;
+}
+
+static union _zend_function *zend_std_get_constructor(zval *object TSRMLS_DC)
+{
+ zend_object *zobj;
+
+ zobj = Z_GET_OBJ(object);
+ return zobj->ce->constructor;
+}
+
+static int zend_std_get_class(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
+{
+ zend_object *zobj;
+ zend_class_entry *ce;
+
+ zobj = Z_GET_OBJ(object);
+ if(parent) {
+ ce = zobj->ce->parent;
+ } else {
+ ce = zobj->ce;
+ }
+ if(!ce) {
+ return FAILURE;
+ }
+
+ *class_name = zobj->ce->name;
+ *class_name_len = zobj->ce->name_length;
+ return SUCCESS;
+}
+
+int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC);
+
+static int zend_std_compare_objects(zval *o1, zval *o2 TSRMLS_DC)
+{
+ zend_object *zobj1, *zobj2;
+
+ zobj1 = Z_GET_OBJ(o1);
+ zobj2 = Z_GET_OBJ(o2);
+
+ if(zobj1->ce != zobj2->ce) {
+ return 1; /* different classes */
+ }
+ return zend_compare_symbol_tables_i(zobj1->properties, zobj2->properties TSRMLS_CC);
+}
+
+static int zend_std_has_property(zval *object, zval *member, int check_empty TSRMLS_DC)
+{
+ zend_object *zobj;
+ int result;
+ zval **value;
+ zval tmp_member;
+
+ zobj = Z_GET_OBJ(object);
+
+ if (member->type != IS_STRING) {
+ tmp_member = *member;
+ zval_copy_ctor(&tmp_member);
+ convert_to_string(&tmp_member);
+ member = &tmp_member;
+ }
+
+ if(zend_hash_find(zobj->properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1, (void **)&value) == SUCCESS) {
+ if(check_empty) {
+ result = zend_is_true(*value);
+ } else {
+ result = (Z_TYPE_PP(value) != IS_NULL);
+ }
+ } else {
+ result = 0;
+ }
+
+ if (member == &tmp_member) {
+ zval_dtor(member);
+ }
+ return result;
+}
+
+zend_object_handlers std_object_handlers = {
+ zend_objects_add_ref, /* add_ref */
+ zend_objects_del_ref, /* del_ref */
+ zend_objects_delete_obj, /* delete_obj */
+ zend_objects_clone_obj, /* clone_obj */
+
+ zend_std_read_property, /* read_property */
+ zend_std_write_property, /* write_property */
+ zend_std_get_property_ptr, /* get_property_ptr */
+ NULL, /* get */
+ NULL, /* set */
+ zend_std_has_property, /* has_property */
+ zend_std_unset_property, /* unset_property */
+ zend_std_get_properties, /* get_properties */
+ zend_std_get_method, /* get_method */
+ NULL, /* call_method */
+ zend_std_get_constructor, /* get_constructor */
+ zend_std_get_class, /* get_class */
+ zend_std_compare_objects /* compare_objects */
+};
+
diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h
new file mode 100644
index 0000000000..21140956ca
--- /dev/null
+++ b/Zend/zend_object_handlers.h
@@ -0,0 +1,73 @@
+#ifndef ZEND_OBJECT_HANDLERS_H
+#define ZEND_OBJECT_HANDLERS_H
+
+union _zend_function;
+
+typedef zval *(*zend_object_read_property_t)(zval *object, zval *member, int type TSRMLS_DC);
+/* Used to fetch property from the object, read-only */
+typedef void (*zend_object_write_property_t)(zval *object, zval *member, zval *value TSRMLS_DC);
+/* Used to set property of the object */
+
+typedef zval **(*zend_object_get_property_ptr_t)(zval *object, zval *member TSRMLS_DC);
+/* Used to create pointer to the property of the object, for future r/w access */
+typedef void (*zend_object_set_t)(zval **property, zval *value TSRMLS_DC);
+/* Used to set object value (most probably used in combination with
+typedef the result of the get_property_ptr) */
+typedef zval* (*zend_object_get_t)(zval *property TSRMLS_DC);
+/* Used to get object value (most probably used in combination with
+the result of the get_property_ptr or when converting object value to
+one of the basic types) */
+
+typedef int (*zend_object_has_property_t)(zval *object, zval *member, int check_empty TSRMLS_DC);
+/* Used to check if a property of the object exists */
+typedef void (*zend_object_unset_property_t)(zval *object, zval *member TSRMLS_DC);
+/* Used to remove a property of the object */
+
+typedef HashTable *(*zend_object_get_properties_t)(zval *object TSRMLS_DC);
+/* Used to get hash of the properties of the object, as hash of zval's */
+
+typedef int (*zend_object_call_method_t)(char *method, INTERNAL_FUNCTION_PARAMETERS);
+/* Used to call methods */
+/* args on stack! */
+/* Andi - EX(fbc) (function being called) needs to be initialized already in the INIT fcall opcode so that the parameters can be parsed the right way. We need to add another callback fror this.
+*/
+typedef union _zend_function *(*zend_object_get_method_t)(zval *object, char *method, int method_len TSRMLS_DC);
+typedef union _zend_function *(*zend_object_get_constructor_t)(zval *object TSRMLS_DC);
+/* Get method parameter mask - by value/by reference, etc. */
+
+/* Object maintenance/destruction */
+typedef void (*zend_object_add_ref_t)(zval *object);
+typedef void (*zend_object_del_ref_t)(zval *object);
+typedef void (*zend_object_delete_obj_t)(zval *object);
+typedef zend_object_value (*zend_object_clone_obj_t)(zval *object);
+
+typedef int (*zend_object_get_class_name_t)(zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC);
+typedef int (*zend_object_compare_t)(zval *object1, zval *object2 TSRMLS_DC);
+
+typedef struct _zend_object_handlers {
+ /* general object functions */
+ zend_object_add_ref_t add_ref;
+ zend_object_del_ref_t del_ref;
+ zend_object_delete_obj_t delete_obj;
+ zend_object_clone_obj_t clone_obj;
+ /* individual object functions */
+ zend_object_read_property_t read_property;
+ zend_object_write_property_t write_property;
+ zend_object_get_property_ptr_t get_property_ptr;
+ zend_object_get_t get;
+ zend_object_set_t set;
+ zend_object_has_property_t has_property;
+ zend_object_unset_property_t unset_property;
+ zend_object_get_properties_t get_properties;
+ zend_object_get_method_t get_method;
+ zend_object_call_method_t call_method;
+ zend_object_get_constructor_t get_constructor;
+ zend_object_get_class_name_t get_class_name;
+ zend_object_compare_t compare_objects;
+} zend_object_handlers;
+
+extern zend_object_handlers std_object_handlers;
+
+#define IS_ZEND_STD_OBJECT(z) ((z).type == IS_OBJECT && Z_OBJ_HT(z) == &std_object_handlers)
+
+#endif
diff --git a/Zend/zend_objects.c b/Zend/zend_objects.c
index ddbbee5f2a..45bb1677ae 100644
--- a/Zend/zend_objects.c
+++ b/Zend/zend_objects.c
@@ -3,16 +3,7 @@
#include "zend_variables.h"
#include "zend_API.h"
-#define ZEND_DEBUG_OBJECTS 0
-
-static zend_object_handlers zoh = {
- zend_objects_get_address,
- NULL,
- zend_objects_add_ref,
- zend_objects_del_ref,
- zend_objects_delete_obj,
- zend_objects_clone_obj
-};
+#define ZEND_DEBUG_OBJECTS 1
void zend_objects_init(zend_objects *objects, zend_uint init_size)
{
@@ -38,7 +29,7 @@ static inline void zend_objects_call_destructor(zend_object *object, zend_object
MAKE_STD_ZVAL(obj);
obj->type = IS_OBJECT;
obj->value.obj.handle = handle;
- obj->value.obj.handlers = &zoh;
+ obj->value.obj.handlers = &std_object_handlers;
zval_copy_ctor(obj);
@@ -110,25 +101,27 @@ zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class
(*object)->ce = class_type;
retval.handle = handle;
- retval.handlers = &zoh;
+ retval.handlers = &std_object_handlers;
#if ZEND_DEBUG_OBJECTS
fprintf(stderr, "Allocated object id #%d\n", handle);
#endif
return retval;
}
-zend_object *zend_objects_get_address(zend_object_handle handle)
+zend_object *zend_objects_get_address(zval *zobject)
{
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
TSRMLS_FETCH();
-
+
if (!EG(objects).object_buckets[handle].valid) {
zend_error(E_ERROR, "Trying to access invalid object");
}
return &EG(objects).object_buckets[handle].bucket.obj.object;
}
-void zend_objects_add_ref(zend_object_handle handle)
+void zend_objects_add_ref(zval *object)
{
+ zend_object_handle handle = Z_OBJ_HANDLE_P(object);
TSRMLS_FETCH();
if (!EG(objects).object_buckets[handle].valid) {
@@ -141,9 +134,10 @@ void zend_objects_add_ref(zend_object_handle handle)
#endif
}
-void zend_objects_delete_obj(zend_object_handle handle)
+void zend_objects_delete_obj(zval *zobject)
{
zend_object *object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
TSRMLS_FETCH();
if (!EG(objects).object_buckets[handle].valid) {
@@ -170,8 +164,9 @@ void zend_objects_delete_obj(zend_object_handle handle)
EG(objects).free_list_head = handle; \
EG(objects).object_buckets[handle].valid = 0;
-void zend_objects_del_ref(zend_object_handle handle)
+void zend_objects_del_ref(zval *zobject)
{
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
TSRMLS_FETCH();
if (--EG(objects).object_buckets[handle].bucket.obj.refcount == 0) {
@@ -202,11 +197,12 @@ void zend_objects_del_ref(zend_object_handle handle)
#endif
}
-zend_object_value zend_objects_clone_obj(zend_object_handle handle)
+zend_object_value zend_objects_clone_obj(zval *zobject)
{
zend_object_value retval;
zend_object *old_object;
zend_object *new_object;
+ zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
TSRMLS_FETCH();
@@ -232,7 +228,7 @@ zend_object_value zend_objects_clone_obj(zend_object_handle handle)
MAKE_STD_ZVAL(old_obj);
old_obj->type = IS_OBJECT;
old_obj->value.obj.handle = handle;
- old_obj->value.obj.handlers = &zoh; /* If we reached here than the handlers are zoh */
+ old_obj->value.obj.handlers = &std_object_handlers; /* If we reached here than the handlers are standrd */
zval_copy_ctor(old_obj);
/* FIXME: Optimize this so that we use the old_object->ce->clone function pointer instead of the name */
diff --git a/Zend/zend_objects.h b/Zend/zend_objects.h
index f068afa8f7..3ae67e4c71 100644
--- a/Zend/zend_objects.h
+++ b/Zend/zend_objects.h
@@ -28,10 +28,14 @@ void zend_objects_init(zend_objects *objects, zend_uint init_size);
void zend_objects_call_destructors(zend_objects *objects TSRMLS_DC);
void zend_objects_destroy(zend_objects *objects);
zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type);
-zend_object *zend_objects_get_address(zend_object_handle handle);
-void zend_objects_add_ref(zend_object_handle handle);
-void zend_objects_del_ref(zend_object_handle handle);
-void zend_objects_delete_obj(zend_object_handle handle);
-zend_object_value zend_objects_clone_obj(zend_object_handle handle);
+
+zend_object *zend_objects_get_address(zval *object);
+
+void zend_objects_add_ref(zval *object);
+void zend_objects_del_ref(zval *object);
+void zend_objects_delete_obj(zval *object);
+zend_object_value zend_objects_clone_obj(zval *object);
+
+#define Z_GET_OBJ(object_zval) zend_objects_get_address(object_zval)
#endif /* ZEND_OBJECTS_H */
diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c
index abb37e4d4e..0695b4606e 100644
--- a/Zend/zend_operators.c
+++ b/Zend/zend_operators.c
@@ -202,7 +202,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC)
(holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
break; \
case IS_OBJECT: \
- (holder).value.lval = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0); \
+ (holder).value.lval = 1; /* TBI!! */ \
break; \
case IS_BOOL: \
case IS_RESOURCE: \
@@ -245,7 +245,7 @@ ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC)
(holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
break; \
case IS_OBJECT: \
- (holder).value.lval = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0); \
+ (holder).value.lval = 1; /* TBI!! */ \
break; \
default: \
(holder).value.lval = 0; \
@@ -294,9 +294,8 @@ ZEND_API void convert_to_long_base(zval *op, int base)
op->value.lval = tmp;
break;
case IS_OBJECT:
- tmp = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
zval_dtor(op);
- op->value.lval = tmp;
+ op->value.lval = 1; /* TBI!! */
break;
default:
zend_error(E_WARNING, "Cannot convert to ordinal value");
@@ -342,9 +341,8 @@ ZEND_API void convert_to_double(zval *op)
op->value.dval = tmp;
break;
case IS_OBJECT:
- tmp = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
zval_dtor(op);
- op->value.dval = tmp;
+ op->value.dval = 1; /* TBI!! */
break;
default:
zend_error(E_WARNING, "Cannot convert to real value (type=%d)", op->type);
@@ -403,9 +401,8 @@ ZEND_API void convert_to_boolean(zval *op)
op->value.lval = tmp;
break;
case IS_OBJECT:
- tmp = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
zval_dtor(op);
- op->value.lval = tmp;
+ op->value.lval = 1; /* TBI!! */
break;
default:
zval_dtor(op);
@@ -510,6 +507,8 @@ static void convert_scalar_to_array(zval *op, int type)
ZEND_API void convert_to_array(zval *op)
{
+ TSRMLS_FETCH();
+
switch(op->type) {
case IS_ARRAY:
return;
@@ -522,7 +521,9 @@ ZEND_API void convert_to_array(zval *op)
ALLOC_HASHTABLE(ht);
zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
- zend_hash_copy(ht, Z_OBJPROP_P(op), (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+ if(Z_OBJ_HT_P(op)->get_properties) {
+ zend_hash_copy(ht, Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
+ }
zval_dtor(op);
op->type = IS_ARRAY;
op->value.ht = ht;
@@ -1253,14 +1254,10 @@ ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
}
break;
case IS_OBJECT:
- if (Z_OBJCE_P(op1) != Z_OBJCE_P(op2)) {
- result->value.lval = 0;
+ if(Z_OBJ_HT_P(op1) == Z_OBJ_HT_P(op2) && Z_OBJ_HANDLE_P(op1) == Z_OBJ_HANDLE_P(op2)) {
+ result->value.lval = 1;
} else {
- if (zend_hash_compare(Z_OBJPROP_P(op1), Z_OBJPROP_P(op2), (compare_func_t) hash_zval_identical_function, 1 TSRMLS_CC)==0) {
- result->value.lval = 1;
- } else {
- result->value.lval = 0;
- }
+ result->value.lval = 0;
}
break;
default:
@@ -1712,6 +1709,11 @@ static int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC
return result.value.lval;
}
+ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC)
+{
+ return zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
+}
+
ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC)
@@ -1729,10 +1731,20 @@ ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC)
ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC)
{
- if (Z_OBJCE_P(o1) != Z_OBJCE_P(o2)) {
+ result->type = IS_LONG;
+ if (Z_OBJ_HT_P(o1) != Z_OBJ_HT_P(o2)) {
result->value.lval = 1; /* Comparing objects of different types is pretty much meaningless */
- result->type = IS_LONG;
return;
}
- zend_compare_symbol_tables(result, Z_OBJPROP_P(o1), Z_OBJPROP_P(o2) TSRMLS_CC);
+
+ if(Z_OBJ_HT_P(o1)->compare_objects == NULL) {
+ if(Z_OBJ_HANDLE_P(o1) == Z_OBJ_HANDLE_P(o2)) {
+ result->value.lval = 0;
+ } else {
+ result->value.lval = 1;
+ }
+ return;
+ } else {
+ result->value.lval = Z_OBJ_HT_P(o1)->compare_objects(o1, o2 TSRMLS_CC);
+ }
}
diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h
index 2957c0d26e..b7e5b878bd 100644
--- a/Zend/zend_operators.h
+++ b/Zend/zend_operators.h
@@ -232,7 +232,9 @@ ZEND_API int zend_atoi(const char *str, int str_len);
#define Z_STRVAL(zval) (zval).value.str.val
#define Z_STRLEN(zval) (zval).value.str.len
#define Z_ARRVAL(zval) (zval).value.ht
-#define Z_OBJ(zval) (zval).value.obj.handlers->get_address((zval).value.obj.handle)
+#define Z_OBJ_HANDLE(zval) (zval).value.obj.handle
+#define Z_OBJ_HT(zval) (zval).value.obj.handlers
+#define Z_OBJ(zval) zend_objects_get_address(&(zval))
#define Z_OBJPROP(zval) Z_OBJ(zval)->properties
#define Z_OBJCE(zval) Z_OBJ(zval)->ce
#define Z_RESVAL(zval) (zval).value.lval
@@ -247,6 +249,8 @@ ZEND_API int zend_atoi(const char *str, int str_len);
#define Z_OBJPROP_P(zval_p) Z_OBJPROP(*zval_p)
#define Z_OBJCE_P(zval_p) Z_OBJCE(*zval_p)
#define Z_RESVAL_P(zval_p) Z_RESVAL(*zval_p)
+#define Z_OBJ_HANDLE_P(zval_p) Z_OBJ_HANDLE(*zval_p)
+#define Z_OBJ_HT_P(zval_p) Z_OBJ_HT(*zval_p)
#define Z_LVAL_PP(zval_pp) Z_LVAL(**zval_pp)
#define Z_BVAL_PP(zval_pp) Z_BVAL(**zval_pp)
@@ -258,6 +262,8 @@ ZEND_API int zend_atoi(const char *str, int str_len);
#define Z_OBJPROP_PP(zval_pp) Z_OBJPROP(**zval_pp)
#define Z_OBJCE_PP(zval_pp) Z_OBJCE(**zval_pp)
#define Z_RESVAL_PP(zval_pp) Z_RESVAL(**zval_pp)
+#define Z_OBJ_HANDLE_PP(zval_p) Z_OBJ_HANDLE(**zval_p)
+#define Z_OBJ_HT_PP(zval_p) Z_OBJ_HT(**zval_p)
#define Z_TYPE(zval) (zval).type
#define Z_TYPE_P(zval_p) Z_TYPE(*zval_p)
diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c
index eb097bbf96..b7846211c0 100644
--- a/Zend/zend_variables.c
+++ b/Zend/zend_variables.c
@@ -54,7 +54,7 @@ ZEND_API void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC)
}
break;
case IS_OBJECT:
- zvalue->value.obj.handlers->del_ref(zvalue->value.obj.handle);
+ Z_OBJ_HT_P(zvalue)->del_ref(zvalue);
break;
case IS_RESOURCE: {
TSRMLS_FETCH();
@@ -122,7 +122,7 @@ ZEND_API int _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
#if 0
zvalue->value.obj = zvalue->value.obj.handlers->clone_obj(zvalue->value.obj.handle);
#else
- zvalue->value.obj.handlers->add_ref(zvalue->value.obj.handle);
+ Z_OBJ_HT_P(zvalue)->add_ref(zvalue);
#endif
break;
}