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.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 zval
*php_property_proxy_zval(zval
*container
, zend_string
*member
)
55 php_property_proxy_t
*proxy
;
56 php_property_proxy_object_t
*proxy_obj
;
58 proxy
= php_property_proxy_init(container
, member
);
59 proxy_obj
= php_property_proxy_object_new_ex(NULL
, proxy
);
61 ZVAL_OBJ(&proxy_obj
->myself
, &proxy_obj
->zo
);
62 return &proxy_obj
->myself
;
65 static zend_class_entry
*php_property_proxy_class_entry
;
66 static zend_object_handlers php_property_proxy_object_handlers
;
68 zend_class_entry
*php_property_proxy_get_class_entry(void)
70 return php_property_proxy_class_entry
;
73 static inline php_property_proxy_object_t
*get_propro(zval
*object
);
74 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value
);
75 static zval
*get_proxied_value(zval
*object
, zval
*return_value
);
76 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value
);
77 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
, int type
);
78 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
);
79 static void set_proxied_value(zval
*object
, zval
*value
);
82 /* we do not really care about TS when debugging */
84 static const char space
[] = " ";
85 static const char *inoutstr
[] = {"< return","="," > enter"};
87 static void _walk(php_property_proxy_object_t
*obj
)
90 if (!Z_ISUNDEF(obj
->parent
)) {
91 _walk(get_propro(&obj
->parent
));
94 fprintf(stderr
, ".%s", obj
->proxy
->member
->val
);
99 static void debug_propro(int inout
, const char *f
,
100 php_property_proxy_object_t
*obj
, zval
*offset
, zval
*value TSRMLS_DC
)
102 fprintf(stderr
, "#PP %p %s %s %s ", obj
, &space
[sizeof(space
)-level
],
103 inoutstr
[inout
+1], f
);
113 char *offset_str
= "[]";
117 convert_to_string_ex(o
);
118 offset_str
= Z_STRVAL_P(o
);
121 fprintf(stderr
, ".%s", offset_str
);
123 if (o
&& o
!= offset
) {
127 if (value
&& !Z_ISUNDEF_P(value
)) {
148 fprintf(stderr
, " = (%s) ", t
[Z_TYPE_P(value
)&0xf]);
149 if (!Z_ISUNDEF_P(value
) && Z_TYPE_P(value
) != IS_INDIRECT
) {
150 zend_print_flat_zval_r(value TSRMLS_CC
);
154 fprintf(stderr
, "\n");
157 #define debug_propro(l, f, obj, off, val)
160 php_property_proxy_object_t
*php_property_proxy_object_new_ex(
161 zend_class_entry
*ce
, php_property_proxy_t
*proxy
)
163 php_property_proxy_object_t
*o
;
166 ce
= php_property_proxy_class_entry
;
169 o
= ecalloc(1, sizeof(*o
) + sizeof(zval
) * (ce
->default_properties_count
- 1));
170 zend_object_std_init(&o
->zo
, ce
);
171 object_properties_init(&o
->zo
, ce
);
174 o
->zo
.handlers
= &php_property_proxy_object_handlers
;
176 debug_propro(0, "init", o
, NULL
, NULL
);
181 zend_object
*php_property_proxy_object_new(zend_class_entry
*ce
)
183 return &php_property_proxy_object_new_ex(ce
, NULL
)->zo
;
186 static void destroy_obj(zend_object
*object
)
188 php_property_proxy_object_t
*o
= PHP_PROPRO_PTR(object
);
190 debug_propro(0, "dtor", o
, NULL
, NULL
);
193 php_property_proxy_free(&o
->proxy
);
195 if (!Z_ISUNDEF(o
->parent
)) {
196 zval_ptr_dtor(&o
->parent
);
197 ZVAL_UNDEF(&o
->parent
);
199 zend_object_std_dtor(object
);
202 static inline php_property_proxy_object_t
*get_propro(zval
*object
)
204 object
= get_referenced_zval(object
);
205 switch (Z_TYPE_P(object
)) {
209 EMPTY_SWITCH_DEFAULT_CASE();
211 return PHP_PROPRO_PTR(Z_OBJ_P(object
));
214 static inline zend_bool
got_value(zval
*container
, zval
*value
)
218 if (!Z_ISUNDEF_P(value
)) {
219 if (SUCCESS
== is_identical_function(&identical
, value
, container
)) {
220 if (Z_TYPE(identical
) != IS_TRUE
) {
229 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value
)
231 php_property_proxy_object_t
*obj
;
233 obj
= get_propro(object
);
234 debug_propro(1, "parent_get", obj
, NULL
, NULL
);
237 if (!Z_ISUNDEF(obj
->parent
)) {
238 get_proxied_value(&obj
->parent
, return_value
);
242 debug_propro(-1, "parent_get", obj
, NULL
, return_value
);
247 static zval
*get_proxied_value(zval
*object
, zval
*return_value
)
249 zval
*hash_value
, *ref
, prop_tmp
;
250 php_property_proxy_object_t
*obj
;
252 obj
= get_propro(object
);
253 debug_propro(1, "get", obj
, NULL
, NULL
);
256 if (!Z_ISUNDEF(obj
->parent
)) {
259 ZVAL_UNDEF(&parent_value
);
260 get_parent_proxied_value(object
, &parent_value
);
262 if (got_value(&obj
->proxy
->container
, &parent_value
)) {
263 zval_ptr_dtor(&obj
->proxy
->container
);
264 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
268 ref
= get_referenced_zval(&obj
->proxy
->container
);
270 switch (Z_TYPE_P(ref
)) {
272 RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(ref
), ref
,
273 obj
->proxy
->member
->val
, obj
->proxy
->member
->len
, 0, &prop_tmp
),
278 hash_value
= zend_symtable_find(Z_ARRVAL_P(ref
), obj
->proxy
->member
);
281 RETVAL_ZVAL(hash_value
, 0, 0);
287 debug_propro(-1, "get", obj
, NULL
, return_value
);
292 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
,
295 get_proxied_value(object
, return_value
);
297 debug_propro(0, "cast", get_propro(object
), NULL
, return_value
);
299 if (!Z_ISUNDEF_P(return_value
)) {
300 convert_to_explicit_type_ex(return_value
, type
);
307 static void set_proxied_value(zval
*object
, zval
*value
)
309 php_property_proxy_object_t
*obj
;
312 obj
= get_propro(object
);
313 debug_propro(1, "set", obj
, NULL
, value TSRMLS_CC
);
316 if (!Z_ISUNDEF(obj
->parent
)) {
319 ZVAL_UNDEF(&parent_value
);
320 get_parent_proxied_value(object
, &parent_value
);
322 if (got_value(&obj
->proxy
->container
, &parent_value
)) {
323 zval_ptr_dtor(&obj
->proxy
->container
);
324 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
328 ref
= get_referenced_zval(&obj
->proxy
->container
);
330 switch (Z_TYPE_P(ref
)) {
332 zend_update_property(Z_OBJCE_P(ref
), ref
, obj
->proxy
->member
->val
,
333 obj
->proxy
->member
->len
, value
);
337 convert_to_array(ref
);
341 Z_TRY_ADDREF_P(value
);
342 zend_symtable_update(Z_ARRVAL_P(ref
), obj
->proxy
->member
, value
);
346 if (!Z_ISUNDEF(obj
->parent
)) {
347 set_proxied_value(&obj
->parent
, &obj
->proxy
->container
);
351 debug_propro(-1, "set", obj
, NULL
, NULL
);
354 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value
)
359 debug_propro(1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref",
360 get_propro(object
), offset
, NULL
);
362 ZVAL_UNDEF(&proxied_value
);
363 get_proxied_value(object
, &proxied_value
);
366 convert_to_string_ex(o
);
369 if (BP_VAR_R
== type
&& o
&& !Z_ISUNDEF(proxied_value
)) {
370 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
371 zval
*hash_value
= zend_symtable_find(Z_ARRVAL(proxied_value
),
375 RETVAL_ZVAL(hash_value
, 1, 0);
380 php_property_proxy_t
*proxy
;
381 php_property_proxy_object_t
*proxy_obj
;
383 if (!Z_ISUNDEF(proxied_value
)) {
384 convert_to_array(&proxied_value
);
385 Z_ADDREF(proxied_value
);
387 array_init(&proxied_value
);
388 set_proxied_value(object
, &proxied_value
);
394 member
= zend_long_to_str(zend_hash_next_free_element(
395 Z_ARRVAL(proxied_value
)));
398 proxy
= php_property_proxy_init(&proxied_value
, member
);
399 zval_ptr_dtor(&proxied_value
);
402 zend_string_release(member
);
405 proxy_obj
= php_property_proxy_object_new_ex(NULL
, proxy
);
406 ZVAL_COPY(&proxy_obj
->parent
, object
);
407 RETVAL_OBJ(&proxy_obj
->zo
);
410 if (o
&& o
!= offset
) {
414 debug_propro(-1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref",
415 get_propro(object
), offset
, return_value
);
420 static int has_dimension(zval
*object
, zval
*offset
, int check_empty
)
425 debug_propro(1, "dim_exists", get_propro(object
), offset
, NULL
);
427 ZVAL_UNDEF(&proxied_value
);
428 get_proxied_value(object
, &proxied_value
);
429 if (Z_ISUNDEF(proxied_value
)) {
432 zend_string
*zs
= zval_get_string(offset
);
434 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
435 zval
*zentry
= zend_symtable_find(Z_ARRVAL(proxied_value
), zs
);
441 exists
= !Z_ISNULL_P(zentry
);
448 zend_string_release(zs
);
451 debug_propro(-1, "dim_exists", get_propro(object
), offset
, NULL
);
456 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
)
460 debug_propro(1, "dim_write", get_propro(object
), offset
, value
);
462 ZVAL_UNDEF(&proxied_value
);
463 get_proxied_value(object
, &proxied_value
);
465 if (!Z_ISUNDEF(proxied_value
)) {
466 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
467 Z_ADDREF(proxied_value
);
469 convert_to_array(&proxied_value
);
472 array_init(&proxied_value
);
475 SEPARATE_ZVAL(value
);
476 Z_TRY_ADDREF_P(value
);
479 zend_string
*zs
= zval_get_string(offset
);
480 zend_symtable_update(Z_ARRVAL(proxied_value
), zs
, value
);
481 zend_string_release(zs
);
483 zend_hash_next_index_insert(Z_ARRVAL(proxied_value
), value
);
486 set_proxied_value(object
, &proxied_value
);
488 debug_propro(-1, "dim_write", get_propro(object
), offset
, &proxied_value
);
490 zval_ptr_dtor(&proxied_value
);
493 static void unset_dimension(zval
*object
, zval
*offset
)
497 debug_propro(1, "dim_unset", get_propro(object
), offset
, NULL
);
499 ZVAL_UNDEF(&proxied_value
);
500 get_proxied_value(object
, &proxied_value
);
502 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
506 convert_to_string_ex(o
);
507 rv
= zend_symtable_del(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
509 set_proxied_value(object
, &proxied_value
);
517 debug_propro(-1, "dim_unset", get_propro(object
), offset
, &proxied_value
);
520 ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct
, 0, 0, 2)
521 ZEND_ARG_INFO(1, object
)
522 ZEND_ARG_INFO(0, member
)
523 ZEND_ARG_OBJ_INFO(0, parent
, php
\\PropertyProxy
, 1)
525 static PHP_METHOD(propro
, __construct
) {
526 zend_error_handling zeh
;
527 zval
*container
, *parent
= NULL
;
530 zend_replace_error_handling(EH_THROW
, NULL
, &zeh
);
531 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "zS|O!",
532 &container
, &member
, &parent
,
533 php_property_proxy_class_entry
)) {
534 php_property_proxy_object_t
*obj
;
535 zval
*ref
= get_referenced_zval(container
);
537 switch (Z_TYPE_P(ref
)) {
542 convert_to_array(ref
);
544 obj
= get_propro(getThis());
545 obj
->proxy
= php_property_proxy_init(container
, member
);
547 ZVAL_COPY(&obj
->parent
, parent
);
550 zend_restore_error_handling(&zeh
);
553 static const zend_function_entry php_property_proxy_method_entry
[] = {
554 PHP_ME(propro
, __construct
, ai_propro_construct
, ZEND_ACC_PUBLIC
)
558 static PHP_MINIT_FUNCTION(propro
)
560 zend_class_entry ce
= {0};
562 INIT_NS_CLASS_ENTRY(ce
, "php", "PropertyProxy",
563 php_property_proxy_method_entry
);
564 php_property_proxy_class_entry
= zend_register_internal_class(&ce
);
565 php_property_proxy_class_entry
->create_object
= php_property_proxy_object_new
;
566 php_property_proxy_class_entry
->ce_flags
|= ZEND_ACC_FINAL
;
568 memcpy(&php_property_proxy_object_handlers
, zend_get_std_object_handlers(),
569 sizeof(zend_object_handlers
));
570 php_property_proxy_object_handlers
.offset
= XtOffsetOf(php_property_proxy_object_t
, zo
);
571 php_property_proxy_object_handlers
.free_obj
= destroy_obj
;
572 php_property_proxy_object_handlers
.set
= set_proxied_value
;
573 php_property_proxy_object_handlers
.get
= get_proxied_value
;
574 php_property_proxy_object_handlers
.cast_object
= cast_proxied_value
;
575 php_property_proxy_object_handlers
.read_dimension
= read_dimension
;
576 php_property_proxy_object_handlers
.write_dimension
= write_dimension
;
577 php_property_proxy_object_handlers
.has_dimension
= has_dimension
;
578 php_property_proxy_object_handlers
.unset_dimension
= unset_dimension
;
583 PHP_MINFO_FUNCTION(propro
)
585 php_info_print_table_start();
586 php_info_print_table_header(2, "Property proxy support", "enabled");
587 php_info_print_table_row(2, "Extension version", PHP_PROPRO_VERSION
);
588 php_info_print_table_end();
591 static const zend_function_entry propro_functions
[] = {
595 zend_module_entry propro_module_entry
= {
596 STANDARD_MODULE_HEADER
,
605 STANDARD_MODULE_PROPERTIES
608 #ifdef COMPILE_DL_PROPRO
609 ZEND_GET_MODULE(propro
)
618 * vim600: noet sw=4 ts=4 fdm=marker
619 * vim<600: noet sw=4 ts=4