Permalink
Browse files

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.
  • Loading branch information...
1 parent 5e9b163 commit 6608f07322789bd0896b265c29e13c0c9f5d5898 @smalyshev smalyshev committed Feb 7, 2002
View
@@ -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@
View
@@ -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
View
@@ -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
View
@@ -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);
View
@@ -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;
View
@@ -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 */
Oops, something went wrong.

0 comments on commit 6608f07

Please sign in to comment.