initial version
[m6w6/ext-propro] / php_propro.c
1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2012 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <php.h>
26 #include <ext/standard/info.h>
27
28 #include "php_propro.h"
29
30 typedef int STATUS;
31
32 PHP_PROPRO_API php_property_proxy_t *php_property_proxy_init(zval *container, const char *member_str, size_t member_len TSRMLS_DC)
33 {
34 php_property_proxy_t *proxy = ecalloc(1, sizeof(*proxy));
35
36 Z_ADDREF_P(container);
37 proxy->container = container;
38 proxy->member_str = estrndup(member_str, member_len);
39 proxy->member_len = member_len;
40
41 return proxy;
42 }
43
44 PHP_PROPRO_API void php_property_proxy_free(php_property_proxy_t **proxy)
45 {
46 if (*proxy) {
47 zval_ptr_dtor(&(*proxy)->container);
48 efree((*proxy)->member_str);
49 efree(*proxy);
50 *proxy = NULL;
51 }
52 }
53
54 static zend_class_entry *php_property_proxy_class_entry;
55 static zend_object_handlers php_property_proxy_object_handlers;
56
57 PHP_PROPRO_API zend_class_entry *php_property_proxy_get_class_entry(void)
58 {
59 return php_property_proxy_class_entry;
60 }
61
62 PHP_PROPRO_API zend_object_value php_property_proxy_object_new(zend_class_entry *ce TSRMLS_DC)
63 {
64 return php_property_proxy_object_new_ex(ce, NULL, NULL TSRMLS_CC);
65 }
66
67 static void php_property_proxy_object_free(void *object TSRMLS_DC)
68 {
69 php_property_proxy_object_t *o = object;
70
71 if (o->proxy) {
72 php_property_proxy_free(&o->proxy);
73 }
74 if (o->parent) {
75 zend_objects_store_del_ref_by_handle_ex(o->parent->zv.handle, o->parent->zv.handlers TSRMLS_CC);
76 o->parent = NULL;
77 }
78 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
79 efree(o);
80 }
81
82 PHP_PROPRO_API zend_object_value php_property_proxy_object_new_ex(zend_class_entry *ce, php_property_proxy_t *proxy, php_property_proxy_object_t **ptr TSRMLS_DC)
83 {
84 php_property_proxy_object_t *o;
85
86 o = ecalloc(1, sizeof(*o));
87 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
88 object_properties_init((zend_object *) o, ce);
89
90 if (ptr) {
91 *ptr = o;
92 }
93 o->proxy = proxy;
94
95 o->zv.handle = zend_objects_store_put(o, NULL, php_property_proxy_object_free, NULL TSRMLS_CC);
96 o->zv.handlers = &php_property_proxy_object_handlers;
97
98 return o->zv;
99 }
100
101 static zval *get_proxied_value(zval *object TSRMLS_DC);
102 static zval *read_dimension(zval *object, zval *offset, int type TSRMLS_DC);
103 static STATUS cast_proxied_value(zval *object, zval *return_value, int type TSRMLS_DC);
104 static void write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC);
105 static void set_proxied_value(zval **object, zval *value TSRMLS_DC);
106
107 static zval *get_proxied_value(zval *object TSRMLS_DC)
108 {
109 zval **hash_value, *value = NULL;
110 php_property_proxy_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
111
112 if (obj->proxy) {
113 switch (Z_TYPE_P(obj->proxy->container)) {
114 case IS_OBJECT:
115 value = zend_read_property(Z_OBJCE_P(obj->proxy->container), obj->proxy->container, obj->proxy->member_str, obj->proxy->member_len, 0 TSRMLS_CC);
116 break;
117
118 case IS_ARRAY:
119 if (SUCCESS == zend_hash_find(Z_ARRVAL_P(obj->proxy->container), obj->proxy->member_str, obj->proxy->member_len + 1, (void *) &hash_value)) {
120 value = *hash_value;
121 }
122 break;
123 }
124 }
125
126 return value;
127 }
128
129 static STATUS cast_proxied_value(zval *object, zval *return_value, int type TSRMLS_DC)
130 {
131 zval *proxied_value;
132
133 if ((proxied_value = get_proxied_value(object TSRMLS_CC))) {
134 RETVAL_ZVAL(proxied_value, 1, 0);
135 if (Z_TYPE_P(proxied_value) != type) {
136 convert_to_explicit_type(return_value, type);
137 }
138 return SUCCESS;
139 }
140
141 return FAILURE;
142 }
143
144 static void set_proxied_value(zval **object, zval *value TSRMLS_DC)
145 {
146 php_property_proxy_object_t *obj = zend_object_store_get_object(*object TSRMLS_CC);
147
148 if (obj->proxy) {
149 switch (Z_TYPE_P(obj->proxy->container)) {
150 case IS_OBJECT:
151 zend_update_property(Z_OBJCE_P(obj->proxy->container), obj->proxy->container, obj->proxy->member_str, obj->proxy->member_len, value TSRMLS_CC);
152 break;
153
154 case IS_ARRAY:
155 Z_ADDREF_P(value);
156 zend_symtable_update(Z_ARRVAL_P(obj->proxy->container), obj->proxy->member_str, obj->proxy->member_len + 1, (void *) &value, sizeof(zval *), NULL);
157 break;
158 }
159
160 if (obj->parent) {
161 zval *zparent;
162 MAKE_STD_ZVAL(zparent);
163 zparent->type = IS_OBJECT;
164 zparent->value.obj = obj->parent->zv;
165 set_proxied_value(&zparent, obj->proxy->container TSRMLS_CC);
166 }
167 }
168 }
169
170 static zval *read_dimension(zval *object, zval *offset, int type TSRMLS_DC)
171 {
172 zval *value = NULL;
173 zval *proxied_value;
174
175 if ((proxied_value = get_proxied_value(object TSRMLS_CC))) {
176 zval *o = offset;
177
178 convert_to_string_ex(&o);
179
180 if (Z_TYPE_P(proxied_value) == IS_ARRAY) {
181 zval **hash_value;
182 if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), Z_STRLEN_P(o), (void *) &hash_value)) {
183 Z_ADDREF_PP(hash_value);
184 value = *hash_value;
185 }
186 }
187
188 if (!value) {
189 zval **hash_value;
190
191 SEPARATE_ZVAL(&proxied_value);
192 convert_to_array(proxied_value);
193
194 MAKE_STD_ZVAL(value);
195 ZVAL_NULL(value);
196 zend_symtable_update(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), Z_STRLEN_P(o) + 1, (void *) &value, sizeof(zval *), (void *) &hash_value);
197 value = *hash_value;
198 Z_SET_ISREF_P(value);
199
200 set_proxied_value(&object, proxied_value TSRMLS_CC);
201 }
202
203 if (o != offset) {
204 zval_ptr_dtor(&o);
205 }
206 }
207
208 return value;
209 }
210
211 static void write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC)
212 {
213 zval *proxied_value;
214
215 if ((proxied_value = get_proxied_value(object TSRMLS_CC))) {
216 zval *o = offset;
217
218 SEPARATE_ZVAL(&proxied_value);
219 convert_to_array(proxied_value);
220
221 if (Z_REFCOUNT_P(value) > 1) {
222 SEPARATE_ZVAL(&value);
223 }
224 Z_ADDREF_P(value);
225
226 if (o) {
227 convert_to_string_ex(&o);
228 zend_symtable_update(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), Z_STRLEN_P(o) + 1, (void *) &value, sizeof(zval *), NULL);
229 } else {
230 zend_hash_next_index_insert(Z_ARRVAL_P(proxied_value), (void *) &value, sizeof(zval *), NULL);
231 }
232
233 if (o != offset) {
234 zval_ptr_dtor(&o);
235 }
236
237 set_proxied_value(&object, proxied_value TSRMLS_CC);
238 }
239 }
240
241 ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct, 0, 0, 2)
242 ZEND_ARG_INFO(0, object)
243 ZEND_ARG_INFO(0, member)
244 ZEND_ARG_OBJ_INFO(0, parent, php\\PropertyProxy, 1)
245 ZEND_END_ARG_INFO();
246 static PHP_METHOD(propro, __construct) {
247 zend_error_handling zeh;
248 zval *container, *parent = NULL;
249 char *member_str;
250 int member_len;
251
252 zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC);
253 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|O!", &container, &member_str, &member_len, &parent, php_property_proxy_class_entry)) {
254 php_property_proxy_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
255
256 obj->proxy = php_property_proxy_init(container, member_str, member_len TSRMLS_CC);
257 if (parent) {
258 zend_objects_store_add_ref(parent TSRMLS_CC);
259 obj->parent = zend_object_store_get_object(parent TSRMLS_CC);
260 }
261 }
262 zend_restore_error_handling(&zeh TSRMLS_CC);
263 }
264
265 static const zend_function_entry php_property_proxy_method_entry[] = {
266 PHP_ME(propro, __construct, ai_propro_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
267 {0}
268 };
269
270 static PHP_MINIT_FUNCTION(propro)
271 {
272 zend_class_entry ce = {0};
273
274 INIT_NS_CLASS_ENTRY(ce, "php", "PropertyProxy", php_property_proxy_method_entry);
275 php_property_proxy_class_entry = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
276 php_property_proxy_class_entry->create_object = php_property_proxy_object_new;
277 php_property_proxy_class_entry->ce_flags |= ZEND_ACC_FINAL_CLASS;
278
279 memcpy(&php_property_proxy_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
280 php_property_proxy_object_handlers.set = set_proxied_value;
281 php_property_proxy_object_handlers.get = get_proxied_value;
282 php_property_proxy_object_handlers.cast_object = cast_proxied_value;
283 php_property_proxy_object_handlers.read_dimension = read_dimension;
284 php_property_proxy_object_handlers.write_dimension = write_dimension;
285
286 return SUCCESS;
287 }
288
289 PHP_MINFO_FUNCTION(propro)
290 {
291 php_info_print_table_start();
292 php_info_print_table_header(2, "Property proxy support", "enabled");
293 php_info_print_table_row(2, "Extension version", PHP_PROPRO_VERSION);
294 php_info_print_table_end();
295 }
296
297 static const zend_function_entry propro_functions[] = {
298 {0}
299 };
300
301 zend_module_entry propro_module_entry = {
302 STANDARD_MODULE_HEADER,
303 "propro",
304 propro_functions,
305 PHP_MINIT(propro),
306 NULL,
307 NULL,
308 NULL,
309 PHP_MINFO(propro),
310 PHP_PROPRO_VERSION,
311 STANDARD_MODULE_PROPERTIES
312 };
313
314 #ifdef COMPILE_DL_PROPRO
315 ZEND_GET_MODULE(propro)
316 #endif
317
318
319 /*
320 * Local variables:
321 * tab-width: 4
322 * c-basic-offset: 4
323 * End:
324 * vim600: noet sw=4 ts=4 fdm=marker
325 * vim<600: noet sw=4 ts=4
326 */