2 +--------------------------------------------------------------------+
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2013 Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
19 #include <ext/standard/info.h>
21 #include "php_propro_api.h"
23 #define DEBUG_PROPRO 0
25 static inline zval
*get_referenced_zval(zval
*ref
)
27 while (Z_ISREF_P(ref
)) {
28 ref
= Z_REFVAL_P(ref
);
33 php_property_proxy_t
*php_property_proxy_init(zval
*container
, zend_string
*member
)
35 php_property_proxy_t
*proxy
= ecalloc(1, sizeof(*proxy
));
37 ZVAL_COPY(&proxy
->container
, get_referenced_zval(container
));
38 proxy
->member
= zend_string_copy(member
);
43 void php_property_proxy_free(php_property_proxy_t
**proxy
)
46 zval_ptr_dtor(&(*proxy
)->container
);
47 zend_string_release((*proxy
)->member
);
53 static zend_class_entry
*php_property_proxy_class_entry
;
54 static zend_object_handlers php_property_proxy_object_handlers
;
56 zend_class_entry
*php_property_proxy_get_class_entry(void)
58 return php_property_proxy_class_entry
;
61 static inline php_property_proxy_object_t
*get_propro(zval
*object
);
62 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value
);
63 static zval
*get_proxied_value(zval
*object
, zval
*return_value
);
64 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value
);
65 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
, int type
);
66 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
);
67 static void set_proxied_value(zval
*object
, zval
*value
);
70 /* we do not really care about TS when debugging */
72 static const char space
[] = " ";
73 static const char *inoutstr
[] = {"< return","="," > enter"};
75 static void _walk(php_property_proxy_object_t
*obj
)
78 if (!Z_ISUNDEF(obj
->parent
)) {
79 _walk(get_propro(&obj
->parent
));
82 fprintf(stderr
, ".%s", obj
->proxy
->member
->val
);
87 static void debug_propro(int inout
, const char *f
,
88 php_property_proxy_object_t
*obj
, zval
*offset
, zval
*value TSRMLS_DC
)
90 fprintf(stderr
, "#PP %p %s %s %s ", obj
, &space
[sizeof(space
)-level
],
91 inoutstr
[inout
+1], f
);
101 char *offset_str
= "[]";
105 convert_to_string_ex(o
);
106 offset_str
= Z_STRVAL_P(o
);
109 fprintf(stderr
, ".%s", offset_str
);
111 if (o
&& o
!= offset
) {
115 if (value
&& !Z_ISUNDEF_P(value
)) {
136 fprintf(stderr
, " = (%s) ", t
[Z_TYPE_P(value
)&0xf]);
137 if (!Z_ISUNDEF_P(value
) && Z_TYPE_P(value
) != IS_INDIRECT
) {
138 zend_print_flat_zval_r(value TSRMLS_CC
);
142 fprintf(stderr
, "\n");
145 #define debug_propro(l, f, obj, off, val)
148 php_property_proxy_object_t
*php_property_proxy_object_new_ex(
149 zend_class_entry
*ce
, php_property_proxy_t
*proxy
)
151 php_property_proxy_object_t
*o
;
154 ce
= php_property_proxy_class_entry
;
157 o
= ecalloc(1, sizeof(*o
) + sizeof(zval
) * (ce
->default_properties_count
- 1));
158 zend_object_std_init(&o
->zo
, ce
);
159 object_properties_init(&o
->zo
, ce
);
162 o
->zo
.handlers
= &php_property_proxy_object_handlers
;
164 debug_propro(0, "init", o
, NULL
, NULL
);
169 zend_object
*php_property_proxy_object_new(zend_class_entry
*ce
)
171 return &php_property_proxy_object_new_ex(ce
, NULL
)->zo
;
174 static void destroy_obj(zend_object
*object
)
176 php_property_proxy_object_t
*o
= PHP_PROPRO_PTR(object
);
178 debug_propro(0, "dtor", o
, NULL
, NULL
);
181 php_property_proxy_free(&o
->proxy
);
183 if (!Z_ISUNDEF(o
->parent
)) {
184 zval_ptr_dtor(&o
->parent
);
185 ZVAL_UNDEF(&o
->parent
);
187 zend_object_std_dtor(object
);
190 static inline php_property_proxy_object_t
*get_propro(zval
*object
)
192 object
= get_referenced_zval(object
);
193 switch (Z_TYPE_P(object
)) {
197 EMPTY_SWITCH_DEFAULT_CASE();
199 return PHP_PROPRO_PTR(Z_OBJ_P(object
));
202 static inline zend_bool
got_value(zval
*container
, zval
*value
)
206 if (!Z_ISUNDEF_P(value
)) {
207 if (SUCCESS
== is_identical_function(&identical
, value
, container
)) {
208 if (Z_TYPE(identical
) != IS_TRUE
) {
217 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value
)
219 php_property_proxy_object_t
*obj
;
221 obj
= get_propro(object
);
222 debug_propro(1, "parent_get", obj
, NULL
, NULL
);
225 if (!Z_ISUNDEF(obj
->parent
)) {
226 get_proxied_value(&obj
->parent
, return_value
);
230 debug_propro(-1, "parent_get", obj
, NULL
, return_value
);
235 static zval
*get_proxied_value(zval
*object
, zval
*return_value
)
237 zval
*hash_value
, *ref
, prop_tmp
;
238 php_property_proxy_object_t
*obj
;
240 obj
= get_propro(object
);
241 debug_propro(1, "get", obj
, NULL
, NULL
);
244 if (!Z_ISUNDEF(obj
->parent
)) {
247 ZVAL_UNDEF(&parent_value
);
248 get_parent_proxied_value(object
, &parent_value
);
250 if (got_value(&obj
->proxy
->container
, &parent_value
)) {
251 zval_ptr_dtor(&obj
->proxy
->container
);
252 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
256 ref
= get_referenced_zval(&obj
->proxy
->container
);
258 switch (Z_TYPE_P(ref
)) {
260 RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(ref
), ref
,
261 obj
->proxy
->member
->val
, obj
->proxy
->member
->len
, 0, &prop_tmp
),
266 hash_value
= zend_symtable_find(Z_ARRVAL_P(ref
), obj
->proxy
->member
);
269 RETVAL_ZVAL(hash_value
, 0, 0);
275 debug_propro(-1, "get", obj
, NULL
, return_value
);
280 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
,
283 get_proxied_value(object
, return_value
);
285 debug_propro(0, "cast", get_propro(object
), NULL
, return_value
);
287 if (!Z_ISUNDEF_P(return_value
)) {
288 convert_to_explicit_type_ex(return_value
, type
);
295 static void set_proxied_value(zval
*object
, zval
*value
)
297 php_property_proxy_object_t
*obj
;
300 obj
= get_propro(object
);
301 debug_propro(1, "set", obj
, NULL
, value TSRMLS_CC
);
304 if (!Z_ISUNDEF(obj
->parent
)) {
307 ZVAL_UNDEF(&parent_value
);
308 get_parent_proxied_value(object
, &parent_value
);
310 if (got_value(&obj
->proxy
->container
, &parent_value
)) {
311 zval_ptr_dtor(&obj
->proxy
->container
);
312 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
316 ref
= get_referenced_zval(&obj
->proxy
->container
);
318 switch (Z_TYPE_P(ref
)) {
320 zend_update_property(Z_OBJCE_P(ref
), ref
, obj
->proxy
->member
->val
,
321 obj
->proxy
->member
->len
, value
);
325 convert_to_array(ref
);
329 Z_TRY_ADDREF_P(value
);
330 zend_symtable_update(Z_ARRVAL_P(ref
), obj
->proxy
->member
, value
);
334 if (!Z_ISUNDEF(obj
->parent
)) {
335 set_proxied_value(&obj
->parent
, &obj
->proxy
->container
);
339 debug_propro(-1, "set", obj
, NULL
, NULL
);
342 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value
)
345 zend_string
*member
= offset
? zval_get_string(offset
) : NULL
;
347 debug_propro(1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref",
348 get_propro(object
), offset
, NULL
);
350 ZVAL_UNDEF(&proxied_value
);
351 get_proxied_value(object
, &proxied_value
);
353 if (BP_VAR_R
== type
&& member
&& !Z_ISUNDEF(proxied_value
)) {
354 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
355 zval
*hash_value
= zend_symtable_find(Z_ARRVAL(proxied_value
),
359 RETVAL_ZVAL(hash_value
, 1, 0);
363 php_property_proxy_t
*proxy
;
364 php_property_proxy_object_t
*proxy_obj
;
366 if (!Z_ISUNDEF(proxied_value
)) {
367 convert_to_array(&proxied_value
);
368 Z_ADDREF(proxied_value
);
370 array_init(&proxied_value
);
371 set_proxied_value(object
, &proxied_value
);
375 member
= zend_long_to_str(zend_hash_next_free_element(
376 Z_ARRVAL(proxied_value
)));
379 proxy
= php_property_proxy_init(&proxied_value
, member
);
380 zval_ptr_dtor(&proxied_value
);
382 proxy_obj
= php_property_proxy_object_new_ex(NULL
, proxy
);
383 ZVAL_COPY(&proxy_obj
->parent
, object
);
384 RETVAL_OBJ(&proxy_obj
->zo
);
388 zend_string_release(member
);
391 debug_propro(-1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref",
392 get_propro(object
), offset
, return_value
);
397 static int has_dimension(zval
*object
, zval
*offset
, int check_empty
)
402 debug_propro(1, "dim_exists", get_propro(object
), offset
, NULL
);
404 ZVAL_UNDEF(&proxied_value
);
405 get_proxied_value(object
, &proxied_value
);
406 if (Z_ISUNDEF(proxied_value
)) {
409 zend_string
*zs
= zval_get_string(offset
);
411 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
412 zval
*zentry
= zend_symtable_find(Z_ARRVAL(proxied_value
), zs
);
418 exists
= !Z_ISNULL_P(zentry
);
425 zend_string_release(zs
);
428 debug_propro(-1, "dim_exists", get_propro(object
), offset
, NULL
);
433 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
)
437 debug_propro(1, "dim_write", get_propro(object
), offset
, value
);
439 ZVAL_UNDEF(&proxied_value
);
440 get_proxied_value(object
, &proxied_value
);
442 if (!Z_ISUNDEF(proxied_value
)) {
443 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
444 Z_ADDREF(proxied_value
);
446 convert_to_array(&proxied_value
);
449 array_init(&proxied_value
);
452 SEPARATE_ZVAL(value
);
453 Z_TRY_ADDREF_P(value
);
456 zend_string
*zs
= zval_get_string(offset
);
457 zend_symtable_update(Z_ARRVAL(proxied_value
), zs
, value
);
458 zend_string_release(zs
);
460 zend_hash_next_index_insert(Z_ARRVAL(proxied_value
), value
);
463 set_proxied_value(object
, &proxied_value
);
465 debug_propro(-1, "dim_write", get_propro(object
), offset
, &proxied_value
);
467 zval_ptr_dtor(&proxied_value
);
470 static void unset_dimension(zval
*object
, zval
*offset
)
474 debug_propro(1, "dim_unset", get_propro(object
), offset
, NULL
);
476 ZVAL_UNDEF(&proxied_value
);
477 get_proxied_value(object
, &proxied_value
);
479 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
483 convert_to_string_ex(o
);
484 rv
= zend_symtable_del(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
486 set_proxied_value(object
, &proxied_value
);
494 debug_propro(-1, "dim_unset", get_propro(object
), offset
, &proxied_value
);
497 ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct
, 0, 0, 2)
498 ZEND_ARG_INFO(1, object
)
499 ZEND_ARG_INFO(0, member
)
500 ZEND_ARG_OBJ_INFO(0, parent
, php
\\PropertyProxy
, 1)
502 static PHP_METHOD(propro
, __construct
) {
503 zend_error_handling zeh
;
504 zval
*container
, *parent
= NULL
;
507 zend_replace_error_handling(EH_THROW
, NULL
, &zeh
);
508 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "zS|O!",
509 &container
, &member
, &parent
,
510 php_property_proxy_class_entry
)) {
511 php_property_proxy_object_t
*obj
;
512 zval
*ref
= get_referenced_zval(container
);
514 switch (Z_TYPE_P(ref
)) {
519 convert_to_array(ref
);
521 obj
= get_propro(getThis());
522 obj
->proxy
= php_property_proxy_init(container
, member
);
524 ZVAL_COPY(&obj
->parent
, parent
);
527 zend_restore_error_handling(&zeh
);
530 static const zend_function_entry php_property_proxy_method_entry
[] = {
531 PHP_ME(propro
, __construct
, ai_propro_construct
, ZEND_ACC_PUBLIC
)
535 static PHP_MINIT_FUNCTION(propro
)
537 zend_class_entry ce
= {0};
539 INIT_NS_CLASS_ENTRY(ce
, "php", "PropertyProxy",
540 php_property_proxy_method_entry
);
541 php_property_proxy_class_entry
= zend_register_internal_class(&ce
);
542 php_property_proxy_class_entry
->create_object
= php_property_proxy_object_new
;
543 php_property_proxy_class_entry
->ce_flags
|= ZEND_ACC_FINAL
;
545 memcpy(&php_property_proxy_object_handlers
, zend_get_std_object_handlers(),
546 sizeof(zend_object_handlers
));
547 php_property_proxy_object_handlers
.offset
= XtOffsetOf(php_property_proxy_object_t
, zo
);
548 php_property_proxy_object_handlers
.free_obj
= destroy_obj
;
549 php_property_proxy_object_handlers
.set
= set_proxied_value
;
550 php_property_proxy_object_handlers
.get
= get_proxied_value
;
551 php_property_proxy_object_handlers
.cast_object
= cast_proxied_value
;
552 php_property_proxy_object_handlers
.read_dimension
= read_dimension
;
553 php_property_proxy_object_handlers
.write_dimension
= write_dimension
;
554 php_property_proxy_object_handlers
.has_dimension
= has_dimension
;
555 php_property_proxy_object_handlers
.unset_dimension
= unset_dimension
;
560 PHP_MINFO_FUNCTION(propro
)
562 php_info_print_table_start();
563 php_info_print_table_header(2, "Property proxy support", "enabled");
564 php_info_print_table_row(2, "Extension version", PHP_PROPRO_VERSION
);
565 php_info_print_table_end();
568 static const zend_function_entry propro_functions
[] = {
572 zend_module_entry propro_module_entry
= {
573 STANDARD_MODULE_HEADER
,
582 STANDARD_MODULE_PROPERTIES
585 #ifdef COMPILE_DL_PROPRO
586 ZEND_GET_MODULE(propro
)
595 * vim600: noet sw=4 ts=4 fdm=marker
596 * vim<600: noet sw=4 ts=4