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
,
34 zend_string
*member TSRMLS_DC
)
36 php_property_proxy_t
*proxy
= ecalloc(1, sizeof(*proxy
));
38 ZVAL_COPY(&proxy
->container
, get_referenced_zval(container
));
39 zend_string_addref(member
);
40 proxy
->member
= member
;
45 void php_property_proxy_free(php_property_proxy_t
**proxy
)
48 zval_ptr_dtor(&(*proxy
)->container
);
49 zend_string_release((*proxy
)->member
);
55 static zend_class_entry
*php_property_proxy_class_entry
;
56 static zend_object_handlers php_property_proxy_object_handlers
;
58 zend_class_entry
*php_property_proxy_get_class_entry(void)
60 return php_property_proxy_class_entry
;
63 static php_property_proxy_object_t
*new_propro(zend_class_entry
*ce
,
64 php_property_proxy_t
*proxy TSRMLS_DC
)
66 php_property_proxy_object_t
*o
;
69 ce
= php_property_proxy_class_entry
;
72 o
= ecalloc(1, sizeof(*o
) + sizeof(zval
) * ce
->default_properties_count
);
73 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
74 object_properties_init((zend_object
*) o
, ce
);
77 o
->zo
.handlers
= &php_property_proxy_object_handlers
;
80 fprintf(stderr
, "#PP %p init\n", o
);
86 static zend_object
*create_obj(zend_class_entry
*ce TSRMLS_DC
)
88 return (zend_object
*) new_propro(ce
, NULL TSRMLS_CC
);
91 static void destroy_obj(zend_object
*object TSRMLS_DC
)
93 php_property_proxy_object_t
*o
= (php_property_proxy_object_t
*) object
;
96 fprintf(stderr
, "#PP %p dtor\n", o
);
100 php_property_proxy_free(&o
->proxy
);
102 if (!Z_ISUNDEF(o
->parent
)) {
103 zval_ptr_dtor(&o
->parent
);
104 ZVAL_UNDEF(&o
->parent
);
108 static inline php_property_proxy_object_t
*get_propro(zval
*object
)
110 object
= get_referenced_zval(object
);
111 switch (Z_TYPE_P(object
)) {
114 EMPTY_SWITCH_DEFAULT_CASE();
116 return (php_property_proxy_object_t
*) Z_OBJ_P(object
);
120 /* we do not really care about TS when debugging */
121 static int level
= 1;
122 static const char space
[] = " ";
123 static const char *inoutstr
[] = {"< return",""," > enter"};
124 static void _walk(php_property_proxy_object_t
*obj
)
127 if (!Z_ISUNDEF(obj
->parent
)) {
128 _walk(get_propro(&obj
->parent
));
130 fprintf(stderr
, ".%s", obj
->proxy
->member
->val
);
134 static void debug_propro(int inout
, const char *f
, zval
*object
, zval
*offset
,
135 zval
*value TSRMLS_DC
)
137 php_property_proxy_object_t
*obj
;
139 obj
= get_propro(object
);
140 fprintf(stderr
, "#PP %p %s %s %s ", obj
, &space
[sizeof(space
)-level
],
141 inoutstr
[inout
+1], f
);
151 char *offset_str
= "[]";
155 convert_to_string_ex(o
);
156 offset_str
= Z_STRVAL_P(o
);
159 fprintf(stderr
, ".%s", offset_str
);
161 if (o
&& o
!= offset
) {
165 if (value
&& !Z_ISUNDEF_P(value
)) {
179 fprintf(stderr
, " = (%s) ", t
[Z_TYPE_P(value
)&0xf]);
180 if (!Z_ISUNDEF_P(value
)) {
181 zend_print_flat_zval_r(value TSRMLS_CC
);
185 fprintf(stderr
, "\n");
188 #define debug_propro(l, f, obj, off, val)
191 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value TSRMLS_DC
);
192 static zval
*get_proxied_value(zval
*object
, zval
*return_value TSRMLS_DC
);
193 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value TSRMLS_DC
);
194 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
, int type TSRMLS_DC
);
195 static void write_dimension(zval
*object
, zval
*offset
, zval
*value TSRMLS_DC
);
196 static void set_proxied_value(zval
*object
, zval
*value TSRMLS_DC
);
198 static inline zend_bool
got_value(zval
*container
, zval
*value TSRMLS_DC
)
202 if (!Z_ISUNDEF_P(value
)) {
203 if (SUCCESS
== is_identical_function(&identical
, value
, container TSRMLS_CC
)) {
204 if (Z_TYPE(identical
) != IS_TRUE
) {
213 static zval
*get_parent_proxied_value(zval
*object
, zval
*return_value TSRMLS_DC
)
215 php_property_proxy_object_t
*obj
;
217 obj
= get_propro(object
);
219 if (!Z_ISUNDEF(obj
->parent
)) {
220 get_proxied_value(&obj
->parent
, return_value TSRMLS_CC
);
227 static zval
*get_proxied_value(zval
*object
, zval
*return_value TSRMLS_DC
)
229 zval
*hash_value
, *ref
;
230 php_property_proxy_object_t
*obj
;
232 obj
= get_propro(object
);
233 debug_propro(1, "get", object
, NULL
, NULL TSRMLS_CC
);
236 if (!Z_ISUNDEF(obj
->parent
)) {
239 ZVAL_UNDEF(&parent_value
);
240 get_parent_proxied_value(object
, &parent_value TSRMLS_CC
);
242 if (got_value(&obj
->proxy
->container
, &parent_value TSRMLS_CC
)) {
243 zval_ptr_dtor(&obj
->proxy
->container
);
244 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
248 ref
= get_referenced_zval(&obj
->proxy
->container
);
250 switch (Z_TYPE_P(ref
)) {
252 RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(ref
),
253 ref
, obj
->proxy
->member
->val
,
254 obj
->proxy
->member
->len
, 0 TSRMLS_CC
), 0, 0);
258 hash_value
= zend_symtable_find(Z_ARRVAL_P(ref
),
262 RETVAL_ZVAL(hash_value
, 0, 0);
265 EMPTY_SWITCH_DEFAULT_CASE();
269 debug_propro(-1, "get", object
, NULL
, return_value TSRMLS_CC
);
274 static ZEND_RESULT_CODE
cast_proxied_value(zval
*object
, zval
*return_value
,
277 if (!Z_ISUNDEF_P(get_proxied_value(object
, return_value TSRMLS_CC
))) {
278 convert_to_explicit_type_ex(return_value
, type
);
285 static void set_proxied_value(zval
*object
, zval
*value TSRMLS_DC
)
287 php_property_proxy_object_t
*obj
;
290 obj
= get_propro(object
);
291 debug_propro(1, "set", object
, NULL
, value TSRMLS_CC
);
294 if (!Z_ISUNDEF(obj
->parent
)) {
297 ZVAL_UNDEF(&parent_value
);
298 get_parent_proxied_value(object
, &parent_value TSRMLS_CC
);
300 if (got_value(&obj
->proxy
->container
, &parent_value TSRMLS_CC
)) {
301 zval_ptr_dtor(&obj
->proxy
->container
);
302 ZVAL_COPY(&obj
->proxy
->container
, &parent_value
);
306 ref
= get_referenced_zval(&obj
->proxy
->container
);
308 switch (Z_TYPE_P(ref
)) {
310 zend_update_property(Z_OBJCE_P(ref
),
311 ref
, obj
->proxy
->member
->val
,
312 obj
->proxy
->member
->len
, value TSRMLS_CC
);
316 Z_TRY_ADDREF_P(value
);
317 zend_symtable_update(Z_ARRVAL_P(ref
),
318 obj
->proxy
->member
, value
);
324 if (!Z_ISUNDEF(obj
->parent
)) {
325 set_proxied_value(&obj
->parent
, &obj
->proxy
->container TSRMLS_CC
);
329 debug_propro(-1, "set", object
, NULL
, NULL TSRMLS_CC
);
332 static zval
*read_dimension(zval
*object
, zval
*offset
, int type
, zval
*return_value TSRMLS_DC
)
337 debug_propro(1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref", object
,
338 offset
, NULL TSRMLS_CC
);
340 ZVAL_UNDEF(&proxied_value
);
341 get_proxied_value(object
, &proxied_value TSRMLS_CC
);
342 convert_to_string_ex(o
);
344 if (BP_VAR_R
== type
&& !Z_ISUNDEF(proxied_value
)) {
345 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
346 zval
*hash_value
= zend_symtable_find(Z_ARRVAL(proxied_value
),
350 RETVAL_ZVAL(hash_value
, 1, 0);
354 php_property_proxy_t
*proxy
;
355 php_property_proxy_object_t
*proxy_obj
;
357 if (!Z_ISUNDEF(proxied_value
)) {
358 convert_to_array(&proxied_value
);
359 Z_ADDREF(proxied_value
);
361 array_init(&proxied_value
);
362 set_proxied_value(object
, &proxied_value TSRMLS_CC
);
365 proxy
= php_property_proxy_init(&proxied_value
, Z_STR_P(o
) TSRMLS_CC
);
366 zval_ptr_dtor(&proxied_value
);
368 proxy_obj
= new_propro(NULL
, proxy TSRMLS_CC
);
370 ZVAL_COPY(&proxy_obj
->parent
, object
);
371 RETVAL_OBJ((zend_object
*) proxy_obj
);
374 if (o
&& o
!= offset
) {
378 debug_propro(-1, type
== BP_VAR_R
? "dim_read" : "dim_read_ref", object
,
379 offset
, return_value TSRMLS_CC
);
384 static int has_dimension(zval
*object
, zval
*offset
, int check_empty TSRMLS_DC
)
389 debug_propro(1, "dim_exists", object
, offset
, NULL TSRMLS_CC
);
391 ZVAL_UNDEF(&proxied_value
);
392 get_proxied_value(object
, &proxied_value TSRMLS_CC
);
393 if (Z_ISUNDEF(proxied_value
)) {
398 convert_to_string_ex(o
);
400 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
401 zval
*zentry
= zend_symtable_find(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
407 exists
= !Z_ISNULL_P(zentry
);
419 debug_propro(-1, "dim_exists", object
, offset
, NULL TSRMLS_CC
);
424 static void write_dimension(zval
*object
, zval
*offset
, zval
*value TSRMLS_DC
)
426 zval proxied_value
, *o
= offset
;
428 debug_propro(1, "dim_write", object
, offset
, value TSRMLS_CC
);
430 ZVAL_UNDEF(&proxied_value
);
431 get_proxied_value(object
, &proxied_value TSRMLS_CC
);
433 if (!Z_ISUNDEF(proxied_value
)) {
434 convert_to_array(&proxied_value
);
435 Z_ADDREF(proxied_value
);
437 array_init(&proxied_value
);
440 SEPARATE_ZVAL(value
);
441 Z_TRY_ADDREF_P(value
);
444 convert_to_string_ex(o
);
445 zend_symtable_update(Z_ARRVAL(proxied_value
), Z_STR_P(o
), value
);
447 zend_hash_next_index_insert(Z_ARRVAL(proxied_value
), value
);
450 if (o
&& o
!= offset
) {
454 set_proxied_value(object
, &proxied_value TSRMLS_CC
);
456 debug_propro(-1, "dim_write", object
, offset
, &proxied_value TSRMLS_CC
);
458 zval_ptr_dtor(&proxied_value
);
461 static void unset_dimension(zval
*object
, zval
*offset TSRMLS_DC
)
465 debug_propro(1, "dim_unset", object
, offset
, NULL TSRMLS_CC
);
467 get_proxied_value(object
, &proxied_value TSRMLS_CC
);
469 if (Z_TYPE(proxied_value
) == IS_ARRAY
) {
473 convert_to_string_ex(o
);
474 rv
= zend_symtable_del(Z_ARRVAL(proxied_value
), Z_STR_P(o
));
476 set_proxied_value(object
, &proxied_value TSRMLS_CC
);
484 debug_propro(-1, "dim_unset", object
, offset
, &proxied_value TSRMLS_CC
);
487 ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct
, 0, 0, 2)
488 ZEND_ARG_INFO(1, object
)
489 ZEND_ARG_INFO(0, member
)
490 ZEND_ARG_OBJ_INFO(0, parent
, php
\\PropertyProxy
, 1)
492 static PHP_METHOD(propro
, __construct
) {
493 zend_error_handling zeh
;
494 zval
*container
, *parent
= NULL
;
497 zend_replace_error_handling(EH_THROW
, NULL
, &zeh TSRMLS_CC
);
498 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "zS|O!",
499 &container
, &member
, &parent
,
500 php_property_proxy_class_entry
)) {
501 php_property_proxy_object_t
*obj
;
503 obj
= get_propro(getThis());
504 obj
->proxy
= php_property_proxy_init(container
, member TSRMLS_CC
);
506 ZVAL_COPY(&obj
->parent
, parent
);
509 zend_restore_error_handling(&zeh TSRMLS_CC
);
512 static const zend_function_entry php_property_proxy_method_entry
[] = {
513 PHP_ME(propro
, __construct
, ai_propro_construct
, ZEND_ACC_PUBLIC
)
517 static PHP_MINIT_FUNCTION(propro
)
519 zend_class_entry ce
= {0};
521 INIT_NS_CLASS_ENTRY(ce
, "php", "PropertyProxy",
522 php_property_proxy_method_entry
);
523 php_property_proxy_class_entry
= zend_register_internal_class(&ce TSRMLS_CC
);
524 php_property_proxy_class_entry
->create_object
= create_obj
;
525 php_property_proxy_class_entry
->ce_flags
|= ZEND_ACC_FINAL_CLASS
;
527 memcpy(&php_property_proxy_object_handlers
, zend_get_std_object_handlers(),
528 sizeof(zend_object_handlers
));
529 php_property_proxy_object_handlers
.dtor_obj
= destroy_obj
;
530 php_property_proxy_object_handlers
.set
= set_proxied_value
;
531 php_property_proxy_object_handlers
.get
= get_proxied_value
;
532 php_property_proxy_object_handlers
.cast_object
= cast_proxied_value
;
533 php_property_proxy_object_handlers
.read_dimension
= read_dimension
;
534 php_property_proxy_object_handlers
.write_dimension
= write_dimension
;
535 php_property_proxy_object_handlers
.has_dimension
= has_dimension
;
536 php_property_proxy_object_handlers
.unset_dimension
= unset_dimension
;
541 PHP_MINFO_FUNCTION(propro
)
543 php_info_print_table_start();
544 php_info_print_table_header(2, "Property proxy support", "enabled");
545 php_info_print_table_row(2, "Extension version", PHP_PROPRO_VERSION
);
546 php_info_print_table_end();
549 static const zend_function_entry propro_functions
[] = {
553 zend_module_entry propro_module_entry
= {
554 STANDARD_MODULE_HEADER
,
563 STANDARD_MODULE_PROPERTIES
566 #ifdef COMPILE_DL_PROPRO
567 ZEND_GET_MODULE(propro
)
576 * vim600: noet sw=4 ts=4 fdm=marker
577 * vim<600: noet sw=4 ts=4