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 zend_string_addref(member
);
39 proxy
->member
= member
;
44 void php_property_proxy_free(php_property_proxy_t
**proxy
)
47 zval_ptr_dtor(&(*proxy
)->container
);
48 zend_string_release((*proxy
)->member
);
54 static zend_class_entry
*php_property_proxy_class_entry
;
55 static zend_object_handlers php_property_proxy_object_handlers
;
57 zend_class_entry
*php_property_proxy_get_class_entry(void)
59 return php_property_proxy_class_entry
;
62 static inline php_property_proxy_object_t
*get_propro(zval
*object
);
63 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value
);
64 static zval
*get_proxied_value(zval
*object
, zval
*return_value
);
65 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value
);
66 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
, int type
);
67 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
);
68 static void set_proxied_value(zval
*object
, zval
*value
);
71 /* we do not really care about TS when debugging */
73 static const char space
[] = " ";
74 static const char *inoutstr
[] = {"< return","="," > enter"};
76 static void _walk(php_property_proxy_object_t
*obj
)
79 if (!Z_ISUNDEF(obj
->parent
)) {
80 _walk(get_propro(&obj
->parent
));
83 fprintf(stderr
, ".%s", obj
->proxy
->member
->val
);
88 static void debug_propro(int inout
, const char *f
,
89 php_property_proxy_object_t
*obj
, zval
*offset
, zval
*value TSRMLS_DC
)
91 fprintf(stderr
, "#PP %p %s %s %s ", obj
, &space
[sizeof(space
)-level
],
92 inoutstr
[inout
+1], f
);
102 char *offset_str
= "[]";
106 convert_to_string_ex(o
);
107 offset_str
= Z_STRVAL_P(o
);
110 fprintf(stderr
, ".%s", offset_str
);
112 if (o
&& o
!= offset
) {
116 if (value
&& !Z_ISUNDEF_P(value
)) {
137 fprintf(stderr
, " = (%s) ", t
[Z_TYPE_P(value
)&0xf]);
138 if (!Z_ISUNDEF_P(value
) && Z_TYPE_P(value
) != IS_INDIRECT
) {
139 zend_print_flat_zval_r(value TSRMLS_CC
);
143 fprintf(stderr
, "\n");
146 #define debug_propro(l, f, obj, off, val)
149 static php_property_proxy_object_t
*new_propro(zend_class_entry
*ce
,
150 php_property_proxy_t
*proxy
)
152 php_property_proxy_object_t
*o
;
155 ce
= php_property_proxy_class_entry
;
158 o
= ecalloc(1, sizeof(*o
) + sizeof(zval
) * (ce
->default_properties_count
- 1));
159 zend_object_std_init(&o
->zo
, ce
);
160 object_properties_init(&o
->zo
, ce
);
163 o
->zo
.handlers
= &php_property_proxy_object_handlers
;
165 debug_propro(0, "init", o
, NULL
, NULL
);
170 static zend_object
*create_obj(zend_class_entry
*ce
)
172 return &new_propro(ce
, NULL
)->zo
;
175 static void destroy_obj(zend_object
*object
)
177 php_property_proxy_object_t
*o
= PHP_PROPRO_PTR(object
);
179 debug_propro(0, "dtor", o
, NULL
, NULL
);
182 php_property_proxy_free(&o
->proxy
);
184 if (!Z_ISUNDEF(o
->parent
)) {
185 zval_ptr_dtor(&o
->parent
);
186 ZVAL_UNDEF(&o
->parent
);
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
;
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),
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 TSRMLS_CC
);
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
)
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
);
354 convert_to_string_ex(o
);
357 if (BP_VAR_R
== type
&& o
&& !Z_ISUNDEF(proxied_value
)) {
358 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
359 zval
*hash_value
= zend_symtable_find(Z_ARRVAL(proxied_value
),
363 RETVAL_ZVAL(hash_value
, 1, 0);
368 php_property_proxy_t
*proxy
;
369 php_property_proxy_object_t
*proxy_obj
;
371 if (!Z_ISUNDEF(proxied_value
)) {
372 convert_to_array(&proxied_value
);
373 Z_ADDREF(proxied_value
);
375 array_init(&proxied_value
);
376 set_proxied_value(object
, &proxied_value
);
382 member
= zend_long_to_str(zend_hash_next_free_element(
383 Z_ARRVAL(proxied_value
)));
386 proxy
= php_property_proxy_init(&proxied_value
, member
);
387 zval_ptr_dtor(&proxied_value
);
390 zend_string_release(member
);
393 proxy_obj
= new_propro(NULL
, proxy
);
394 ZVAL_COPY(&proxy_obj
->parent
, object
);
395 RETVAL_OBJ(&proxy_obj
->zo
);
398 if (o
&& o
!= offset
) {
402 debug_propro(-1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref",
403 get_propro(object
), offset
, return_value
);
408 static int has_dimension(zval
*object
, zval
*offset
, int check_empty
)
413 debug_propro(1, "dim_exists", get_propro(object
), offset
, NULL
);
415 ZVAL_UNDEF(&proxied_value
);
416 get_proxied_value(object
, &proxied_value
);
417 if (Z_ISUNDEF(proxied_value
)) {
422 convert_to_string_ex(o
);
424 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
425 zval
*zentry
= zend_symtable_find(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
431 exists
= !Z_ISNULL_P(zentry
);
443 debug_propro(-1, "dim_exists", get_propro(object
), offset
, NULL
);
448 static void write_dimension(zval
*object
, zval
*offset
, zval
*value
)
450 zval proxied_value
, *o
= offset
;
452 debug_propro(1, "dim_write", get_propro(object
), offset
, value
);
454 ZVAL_UNDEF(&proxied_value
);
455 get_proxied_value(object
, &proxied_value
);
457 if (!Z_ISUNDEF(proxied_value
)) {
458 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
459 Z_ADDREF(proxied_value
);
461 convert_to_array(&proxied_value
);
464 array_init(&proxied_value
);
467 SEPARATE_ZVAL(value
);
468 Z_TRY_ADDREF_P(value
);
471 convert_to_string_ex(o
);
472 zend_symtable_update(Z_ARRVAL(proxied_value
), Z_STR_P(o
), value
);
474 zend_hash_next_index_insert(Z_ARRVAL(proxied_value
), value
);
477 if (o
&& o
!= offset
) {
481 set_proxied_value(object
, &proxied_value
);
483 debug_propro(-1, "dim_write", get_propro(object
), offset
, &proxied_value
);
485 zval_ptr_dtor(&proxied_value
);
488 static void unset_dimension(zval
*object
, zval
*offset
)
492 debug_propro(1, "dim_unset", get_propro(object
), offset
, NULL
);
494 get_proxied_value(object
, &proxied_value TSRMLS_CC
);
496 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
500 convert_to_string_ex(o
);
501 rv
= zend_symtable_del(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
503 set_proxied_value(object
, &proxied_value
);
511 debug_propro(-1, "dim_unset", get_propro(object
), offset
, &proxied_value
);
514 ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct
, 0, 0, 2)
515 ZEND_ARG_INFO(1, object
)
516 ZEND_ARG_INFO(0, member
)
517 ZEND_ARG_OBJ_INFO(0, parent
, php
\\PropertyProxy
, 1)
519 static PHP_METHOD(propro
, __construct
) {
520 zend_error_handling zeh
;
521 zval
*container
, *parent
= NULL
;
524 zend_replace_error_handling(EH_THROW
, NULL
, &zeh
);
525 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS(), "zS|O!",
526 &container
, &member
, &parent
,
527 php_property_proxy_class_entry
)) {
528 php_property_proxy_object_t
*obj
;
529 zval
*ref
= get_referenced_zval(container
);
531 switch (Z_TYPE_P(ref
)) {
536 convert_to_array(ref
);
538 obj
= get_propro(getThis());
539 obj
->proxy
= php_property_proxy_init(container
, member
);
541 ZVAL_COPY(&obj
->parent
, parent
);
544 zend_restore_error_handling(&zeh
);
547 static const zend_function_entry php_property_proxy_method_entry
[] = {
548 PHP_ME(propro
, __construct
, ai_propro_construct
, ZEND_ACC_PUBLIC
)
552 static PHP_MINIT_FUNCTION(propro
)
554 zend_class_entry ce
= {0};
556 INIT_NS_CLASS_ENTRY(ce
, "php", "PropertyProxy",
557 php_property_proxy_method_entry
);
558 php_property_proxy_class_entry
= zend_register_internal_class(&ce
);
559 php_property_proxy_class_entry
->create_object
= create_obj
;
560 php_property_proxy_class_entry
->ce_flags
|= ZEND_ACC_FINAL
;
562 memcpy(&php_property_proxy_object_handlers
, zend_get_std_object_handlers(),
563 sizeof(zend_object_handlers
));
564 php_property_proxy_object_handlers
.offset
= XtOffsetOf(php_property_proxy_object_t
, zo
);
565 php_property_proxy_object_handlers
.dtor_obj
= destroy_obj
;
566 php_property_proxy_object_handlers
.set
= set_proxied_value
;
567 php_property_proxy_object_handlers
.get
= get_proxied_value
;
568 php_property_proxy_object_handlers
.cast_object
= cast_proxied_value
;
569 php_property_proxy_object_handlers
.read_dimension
= read_dimension
;
570 php_property_proxy_object_handlers
.write_dimension
= write_dimension
;
571 php_property_proxy_object_handlers
.has_dimension
= has_dimension
;
572 php_property_proxy_object_handlers
.unset_dimension
= unset_dimension
;
577 PHP_MINFO_FUNCTION(propro
)
579 php_info_print_table_start();
580 php_info_print_table_header(2, "Property proxy support", "enabled");
581 php_info_print_table_row(2, "Extension version", PHP_PROPRO_VERSION
);
582 php_info_print_table_end();
585 static const zend_function_entry propro_functions
[] = {
589 zend_module_entry propro_module_entry
= {
590 STANDARD_MODULE_HEADER
,
599 STANDARD_MODULE_PROPERTIES
602 #ifdef COMPILE_DL_PROPRO
603 ZEND_GET_MODULE(propro
)
612 * vim600: noet sw=4 ts=4 fdm=marker
613 * vim<600: noet sw=4 ts=4