Skip to content

Commit 6608f07

Browse files
committed
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.
1 parent 5e9b163 commit 6608f07

19 files changed

+825
-345
lines changed

Zend/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ libZend_la_SOURCES=\
1313
zend_opcode.c zend_operators.c zend_ptr_stack.c zend_stack.c \
1414
zend_variables.c zend.c zend_API.c zend_extensions.c zend_hash.c \
1515
zend_list.c zend_indent.c zend_builtin_functions.c zend_sprintf.c \
16-
zend_ini.c zend_qsort.c zend_objects.c
16+
zend_ini.c zend_qsort.c zend_objects.c zend_object_handlers.c
1717

1818
libZend_la_LDFLAGS =
1919
libZend_la_LIBADD = @ZEND_EXTRA_LIBS@

Zend/OBJECTS2_HOWTO

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
Creating an object
2+
------------------
3+
4+
Object can be created in the following ways:
5+
6+
1. As a result of a function call. E.g.:
7+
8+
$foo = create_new_foo("parameter");
9+
$foo->run();
10+
11+
The function should create a new zval, create new object and get the
12+
handle for it, set handle and handler table as needed. Note that the
13+
handle is the only ID of the object, so it should be enough to
14+
identify it.
15+
16+
2. Overriding create_object handler for class. E.g.:
17+
18+
$foo = new Java("some.Class.here", "parameter");
19+
$foo->run();
20+
21+
The create_object handler function should create a new zval, create
22+
new object and get the handle for it, set handle and handler table as
23+
needed, and also provide constructor method that would handle
24+
constructor call. The get_constructor handler table entry should be
25+
used for that. Do not rely class entry's constructor, unless you refer
26+
to it from get_constructor handler.
27+
28+
Object maintenance
29+
------------------
30+
31+
The handlers add_ref and del_ref are called when a new zval referring
32+
to the object is created. This does not create a new object - both
33+
zvals still refer to the same object.
34+
35+
clone_obj handler should create a new object, identical to an old one,
36+
but being a separate entity.
37+
38+
delete_obj should destroy an object, all references to it become
39+
invalid.
40+
41+
Object access - read
42+
--------------------
43+
44+
get_property is used to read object's property. This value is not
45+
meant to be changed. The handler returns zval * with the value.
46+
47+
Object access - write
48+
---------------------
49+
50+
write_property is used to directly write object's property by
51+
name. This handler is not oftenly used by the engine itself, but may
52+
be used by some internal functions.
53+
54+
get_property_ptr is used to obtain zval ** for future writing to
55+
it. If your object properties are stored as zval*, return real place
56+
where the property is stored. If the aren't, the best way is to create
57+
proxy object and handle it via get and set methods (see below).
58+
59+
get and set handlers are used when engine needs to access the object
60+
as a value. E.g., in the following situation:
61+
62+
$foo =& $obj->bar;
63+
$foo = 1;
64+
65+
if $foo is an object (e.g., proxy object from get_property_ptr) it
66+
would be accessed using write handler.
67+
68+
Object access - method call
69+
---------------------------
70+
71+
get_method handler is used to find method description by name. It
72+
should set right type, function name and parameter mask for the
73+
method. If the type is ZEND_OVERLOADED_FUNCTION, the method would be
74+
called via call_method handler, otherwise it would be called with
75+
standard Zend means.
76+
77+
get_constructor performs the same function as get_method, but for the
78+
object constructor.
79+
80+
call_method handler is used to perform method call. Parameters are
81+
passed like to any other Zend internal function.
82+
83+
Object - comparison
84+
-------------------
85+
86+
Objects can be compared via compare_objects handler. This is used with
87+
== operation, === compares objects by handles, i.e., return true if
88+
and only if it's really the same object. Note that objects from
89+
different object types (i.e., having different handlers) can not be
90+
compared.
91+
92+
Objects - reflection
93+
--------------------
94+
95+
get_class_name is used to retrieve class name of the object. No other
96+
reflection functions are currently implemented.
97+
98+
Objects - data structures and handlers
99+
---------------------------------------
100+
101+
The object is represented by the following structure:
102+
103+
struct _zend_object_value {
104+
zend_object_handle handle;
105+
zend_object_handlers *handlers;
106+
};
107+
108+
handle is an ID of the object among the objects of the same type (not
109+
class!). The type of the object and how it behaves is determined by
110+
the handler table.
111+
112+
typedef struct _zend_object_handlers {
113+
zend_object_add_ref_t add_ref;
114+
zend_object_del_ref_t del_ref;
115+
zend_object_delete_obj_t delete_obj;
116+
zend_object_clone_obj_t clone_obj;
117+
zend_object_read_property_t read_property;
118+
zend_object_write_property_t write_property;
119+
zend_object_get_property_ptr_t get_property_ptr;
120+
zend_object_get_t get;
121+
zend_object_set_t set;
122+
zend_object_has_property_t has_property;
123+
zend_object_unset_property_t unset_property;
124+
zend_object_get_properties_t get_properties;
125+
zend_object_get_method_t get_method;
126+
zend_object_call_method_t call_method;
127+
zend_object_get_constructor_t get_constructor;
128+
zend_object_get_class_name_t get_class_name;
129+
zend_object_compare_t compare_objects;
130+
} zend_object_handlers;
131+
132+
See zend_object_handlers.h for prototypes. All objects are passed as zval's.
133+
134+
Handlers explained:
135+
136+
add_ref - called when a copy of the object handle is created.
137+
138+
del_ref - called when a copy of the object handle is destroyed.
139+
140+
delete_obj - called when an object needs to be destroyed.
141+
142+
clone_obj - called when a new object identical to an old one should be
143+
created (unlike Zend Engine 1, this never happens unless explicitly
144+
asked for).
145+
146+
read_property - returns zval *, containing the value of the
147+
property. Is used when value of the property should be retrieved for
148+
reading.
149+
150+
write_property - assigns value to certain property of the object.
151+
152+
get_property_ptr - retrieves zval** for the property of the value, to
153+
be used for read and write. If object properties are not zval's
154+
natively, this method should create and return proxy object for use
155+
with get and set methods.
156+
157+
get - retrieves zval* for object contents. To be used mainly with
158+
proxy objects from get_property_ptr, but also may be used for
159+
convert_to_* functions.
160+
161+
set - sets value for object contents. To be used mainly with
162+
proxy objects from get_property_ptr.
163+
164+
has_property - checks if the object has certain property set.
165+
166+
unset_property - removes value for the property of the object
167+
168+
get_method - retrieves description of the method
169+
170+
call_method - calls the method (parameters should be put on stack like
171+
for any other PHP internal function).
172+
173+
get_constructor - get description for the object constructor method
174+
175+
get_class_name - get the name of the class the object belongs to
176+
177+
compare_objects - compares if two objects are equal

Zend/ZendTS.dsp

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend.h

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -198,32 +198,15 @@ typedef struct _zend_object {
198198
} zend_object;
199199

200200
typedef unsigned int zend_object_handle;
201+
typedef struct _zend_object_value zend_object_value;
201202

202-
typedef struct _zend_object_handlers zend_object_handlers;
203+
#include "zend_object_handlers.h"
203204

204-
typedef struct _zend_object_value {
205+
struct _zend_object_value {
205206
zend_object_handle handle;
206207
zend_object_handlers *handlers;
207-
} zend_object_value;
208-
209-
typedef zend_object *(*get_address_t)(zend_object_handle handle); /* Don't return zval ** so that we can't change it */
210-
typedef zval **(*get_property_address_t)(zend_object_handle handle, zval *offset, int type);
211-
typedef void (*add_ref_t)(zend_object_handle handle);
212-
typedef void (*del_ref_t)(zend_object_handle handle);
213-
typedef void (*delete_obj_t)(zend_object_handle handle);
214-
typedef zend_object_value (*clone_obj_t)(zend_object_handle handle);
215-
216-
struct _zend_object_handlers {
217-
get_address_t get_address;
218-
get_property_address_t get_property_address;
219-
add_ref_t add_ref;
220-
del_ref_t del_ref;
221-
delete_obj_t delete_obj;
222-
clone_obj_t clone_obj;
223208
};
224209

225-
#include "zend_objects.h"
226-
227210
typedef union _zvalue_value {
228211
long lval; /* long value */
229212
double dval; /* double value */
@@ -297,6 +280,7 @@ struct _zend_class_entry {
297280
union _zend_function *clone;
298281

299282
/* handlers */
283+
zend_object_value (*create_object)(zend_class_entry *class_type);
300284
void (*handle_function_call)(INTERNAL_FUNCTION_PARAMETERS, zend_property_reference *property_reference);
301285
zval (*handle_property_get)(zend_property_reference *property_reference);
302286
int (*handle_property_set)(zend_property_reference *property_reference, zval *value);

Zend/zend_API.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ static int zend_check_class(zval *obj, zend_class_entry *expected_ce)
206206
return 0;
207207
}
208208

209+
/* TBI!! new object handlers */
210+
if(!IS_ZEND_STD_OBJECT(*obj)) {
211+
return 0;
212+
}
213+
209214
for (ce = Z_OBJCE_P(obj); ce != NULL; ce = ce->parent) {
210215
if (ce == expected_ce) {
211216
return 1;
@@ -577,15 +582,18 @@ ZEND_API int _object_and_properties_init(zval *arg, zend_class_entry *class_type
577582
}
578583

579584
arg->type = IS_OBJECT;
580-
arg->value.obj = zend_objects_new(&object, class_type);
581-
582-
if (properties) {
583-
object->properties = properties;
585+
if(class_type->create_object == NULL) {
586+
arg->value.obj = zend_objects_new(&object, class_type);
587+
if (properties) {
588+
object->properties = properties;
589+
} else {
590+
ALLOC_HASHTABLE_REL(object->properties);
591+
zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
592+
zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
593+
}
584594
} else {
585-
ALLOC_HASHTABLE_REL(object->properties);
586-
zend_hash_init(object->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
587-
zend_hash_copy(object->properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
588-
}
595+
arg->value.obj = class_type->create_object(class_type);
596+
}
589597
return SUCCESS;
590598
}
591599

@@ -1344,7 +1352,7 @@ zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callabl
13441352
zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(obj) + 1, (void**)&ce);
13451353
efree(lcname);
13461354
} else {
1347-
ce = Z_OBJCE_PP(obj);
1355+
ce = Z_OBJCE_PP(obj); /* ??? */
13481356

13491357
if (callable_name) {
13501358
char *ptr;

Zend/zend_API.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
class_container.constructor = NULL; \
9191
class_container.destructor = NULL; \
9292
class_container.clone = NULL; \
93+
class_container.create_object = NULL; \
9394
class_container.handle_function_call = NULL; \
9495
class_container.handle_property_get = NULL; \
9596
class_container.handle_property_set = NULL; \
@@ -103,6 +104,7 @@
103104
class_container.constructor = NULL; \
104105
class_container.destructor = NULL; \
105106
class_container.clone = NULL; \
107+
class_container.create_object = NULL; \
106108
class_container.handle_function_call = handle_fcall; \
107109
class_container.handle_property_get = handle_propget; \
108110
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,
406408
#define ZEND_SET_GLOBAL_VAR_WITH_LENGTH(name, name_length, var, _refcount, _is_ref) \
407409
ZEND_SET_SYMBOL_WITH_LENGTH(&EG(symbol_table), name, name_length, var, _refcount, _is_ref)
408410

409-
#define HASH_OF(p) ((p)->type==IS_ARRAY ? (p)->value.ht : (((p)->type==IS_OBJECT ? Z_OBJPROP_P(p) : NULL)))
411+
#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)))
410412
#define ZVAL_IS_NULL(z) ((z)->type==IS_NULL)
411413

412414
/* For compatibility */

0 commit comments

Comments
 (0)