X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-propro;a=blobdiff_plain;f=src%2Fphp_propro_api.c;h=631f707c3a9a77d9944c77240851a0df6ff4489e;hp=d7232b36b3a4b2025360667ee07f597ac8a9abe9;hb=HEAD;hpb=8e6c28e6e5c9ef473c705f49a4b9f30ed774231b diff --git a/src/php_propro_api.c b/src/php_propro_api.c index d7232b3..631f707 100644 --- a/src/php_propro_api.c +++ b/src/php_propro_api.c @@ -20,44 +20,191 @@ #include "php_propro_api.h" -#if PHP_VERSION_ID < 50500 -#undef SUCCESS -#undef FAILURE -typedef enum { - SUCCESS = 0, - FAILURE = -1 -} ZEND_RESULT_CODE; -#endif - #define DEBUG_PROPRO 0 -#if PHP_VERSION_ID < 50400 -# define object_properties_init(o, ce) \ - zend_hash_copy(((zend_object *) o)->properties, &(ce->default_properties), \ - (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*)) +static inline php_property_proxy_object_t *get_propro(zval *object); +static inline zval *get_proxied_value(zval *object, zval *return_value); +static inline void set_proxied_value(zval *object, zval *value); + +static zval *read_dimension(zval *object, zval *offset, int type, zval *return_value); +static ZEND_RESULT_CODE cast_obj(zval *object, zval *return_value, int type); +static void write_dimension(zval *object, zval *offset, zval *input_value); + +#if DEBUG_PROPRO +/* we do not really care about TS when debugging */ +static int level = 1; +static const char *inoutstr[] = {"< return","= "," > enter "}; +static const char *types[] = { + "UNDEF", + "NULL", + "FALSE", + "TRUE", + "int", + "float", + "string", + "Array", + "Object", + "resource", + "reference", + "constant", + "const AST", + "_BOOL", + "callable", + "indirect", + "---", + "pointer" +}; + +static const char *_type(zval *zv) +{ + switch (Z_TYPE_P(zv)) { + case IS_OBJECT: + if (zv->value.obj->ce == php_property_proxy_get_class_entry()) { + return "PROPRO"; + } + /* no break */ + default: + return types[Z_TYPE_P(zv)]; + } +} + +static int _walk(php_property_proxy_object_t *obj) +{ + int p = 0; + + if (obj) { + if (!Z_ISUNDEF(obj->parent)) { + p += _walk(get_propro(&obj->parent)); + } + if (obj->proxy) { + p += fprintf(stderr, ".%s", obj->proxy->member->val); + } + } + + return p; +} + +static inline zval *get_container(zval *object, zval *tmp); +static inline zval *get_container_value(zval *container, zend_string *member, zval *return_value); + +static void debug_propro(int inout, const char *f, + php_property_proxy_object_t *obj, + php_property_proxy_t *proxy, + zval *offset, zval *value) +{ + int width; + zval tmp, *container = &tmp; + + if (!proxy && obj) { + proxy = obj->proxy; + } + + fprintf(stderr, "#PP %14p %*c %s %s\t", proxy, level, ' ', inoutstr[inout + 1], f); + + level += inout; + + if (proxy) { + ZVAL_UNDEF(&tmp); + if (!obj) { + container = &proxy->container; + } else if (Z_ISUNDEF(obj->parent)) { + container = &obj->proxy->container; + } + fprintf(stderr, " container= %-14p < %-10s rc=%-2d%s> ", + Z_REFCOUNTED_P(container) ? Z_COUNTED_P(container) : NULL, + _type(container), + Z_REFCOUNTED_P(container) ? Z_REFCOUNT_P(container) : 0, + Z_ISREF_P(container) ? "(ref) ":"(noref)"); + } + + width = _walk(obj); + + if (*f++=='d' + && *f++=='i' + && *f++=='m' + ) { + char *offset_str = "[]"; + zval *o = offset; + + if (o) { + convert_to_string_ex(o); + offset_str = Z_STRVAL_P(o); + } + + width += fprintf(stderr, ".%s", offset_str); + + if (o && o != offset) { + zval_ptr_dtor(o); + } + } + if (value) { + fprintf(stderr, "%.*s", 32-width, " "); + if (Z_ISUNDEF_P(value)) { + fprintf(stderr, " = UNDEF"); + } else { + fprintf(stderr, " = %-14p < %-10s rc=%-2d%s> ", + Z_REFCOUNTED_P(value) ? Z_COUNTED_P(value) : NULL, + _type(value), + Z_REFCOUNTED_P(value) ? Z_REFCOUNT_P(value) : 0, + Z_ISREF_P(value) ? "(ref) " : "(noref)"); + if (!Z_ISUNDEF_P(value) && Z_TYPE_P(value) != IS_INDIRECT) { + zend_print_flat_zval_r(value TSRMLS_CC); + } + } + } + + fprintf(stderr, "\n"); +} +#else +#define debug_propro(l, f, obj, proxy, off, val) #endif -php_property_proxy_t *php_property_proxy_init(zval *container, - const char *member_str, size_t member_len TSRMLS_DC) +php_property_proxy_t *php_property_proxy_init(zval *container, zend_string *member) { php_property_proxy_t *proxy = ecalloc(1, sizeof(*proxy)); +#if DEBUG_PROPRO + zval offset; - Z_ADDREF_P(container); - proxy->container = container; - proxy->member_str = estrndup(member_str, member_len); - proxy->member_len = member_len; + ZVAL_STR_COPY(&offset, member); +#endif + + if (container) { + ZVAL_COPY(&proxy->container, container); + } + proxy->member = zend_string_copy(member); + + debug_propro(0, "init", NULL, proxy, &offset, NULL); + +#if DEBUG_PROPRO + zval_dtor(&offset); +#endif return proxy; } void php_property_proxy_free(php_property_proxy_t **proxy) { +#if DEBUG_PROPRO + zval offset; + + ZVAL_STR_COPY(&offset, (*proxy)->member); + debug_propro(0, "free", NULL, *proxy, &offset, NULL); +#endif + if (*proxy) { - zval_ptr_dtor(&(*proxy)->container); - efree((*proxy)->member_str); + if (!Z_ISUNDEF((*proxy)->container)) { + zval_ptr_dtor(&(*proxy)->container); + ZVAL_UNDEF(&(*proxy)->container); + } + zend_string_release((*proxy)->member); + (*proxy)->member = NULL; efree(*proxy); *proxy = NULL; } + +#if DEBUG_PROPRO + zval_dtor(&offset); +#endif } static zend_class_entry *php_property_proxy_class_entry; @@ -68,456 +215,447 @@ zend_class_entry *php_property_proxy_get_class_entry(void) return php_property_proxy_class_entry; } -zend_object_value php_property_proxy_object_new(zend_class_entry *ce TSRMLS_DC) +php_property_proxy_object_t *php_property_proxy_object_new_ex( + zend_class_entry *ce, php_property_proxy_t *proxy) { - return php_property_proxy_object_new_ex(ce, NULL, NULL TSRMLS_CC); + php_property_proxy_object_t *o; + + if (!ce) { + ce = php_property_proxy_class_entry; + } + + o = ecalloc(1, sizeof(*o) + sizeof(zval) * (ce->default_properties_count - 1)); + zend_object_std_init(&o->zo, ce); + object_properties_init(&o->zo, ce); + + o->proxy = proxy; + o->zo.handlers = &php_property_proxy_object_handlers; + + return o; } -static void php_property_proxy_object_free(void *object TSRMLS_DC) +zend_object *php_property_proxy_object_new(zend_class_entry *ce) { - php_property_proxy_object_t *o = object; + return &php_property_proxy_object_new_ex(ce, NULL)->zo; +} -#if DEBUG_PROPRO - fprintf(stderr, "#PP %p free\n", o); -#endif +static void destroy_obj(zend_object *object) +{ + php_property_proxy_object_t *o = PHP_PROPRO_PTR(object); if (o->proxy) { php_property_proxy_free(&o->proxy); } - if (o->parent) { - zend_objects_store_del_ref_by_handle_ex(o->parent->zv.handle, - o->parent->zv.handlers TSRMLS_CC); - o->parent = NULL; + if (!Z_ISUNDEF(o->parent)) { + zval_ptr_dtor(&o->parent); + ZVAL_UNDEF(&o->parent); } - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); + zend_object_std_dtor(object); } -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) +static inline php_property_proxy_object_t *get_propro(zval *object) { - php_property_proxy_object_t *o; + ZEND_ASSERT(Z_TYPE_P(object) == IS_OBJECT); + return PHP_PROPRO_PTR(Z_OBJ_P(object)); +} - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); +static HashTable *get_gc(zval *object, zval **table, int *n) +{ + php_property_proxy_object_t *o = get_propro(object); - if (ptr) { - *ptr = o; + if (Z_ISUNDEF(o->parent)) { + *table = &o->proxy->container; + } else { + *table = &o->parent; } - o->proxy = proxy; + *n = 1; + return NULL; +} - o->zv.handle = zend_objects_store_put(o, NULL, - php_property_proxy_object_free, NULL TSRMLS_CC); - o->zv.handlers = &php_property_proxy_object_handlers; +static HashTable *get_debug_info(zval *object, int *is_temp) +{ + HashTable *ht; + zval *zmember; + php_property_proxy_object_t *obj = get_propro(object); -#if DEBUG_PROPRO - fprintf(stderr, "#PP %p init\n", o); -#endif + ALLOC_HASHTABLE(ht); + zend_hash_init(ht, 3, NULL, NULL, 0); - return o->zv; + if (Z_ISUNDEF(obj->parent)) { + zend_hash_str_add_empty_element(ht, "parent", sizeof("parent")-1); + zend_hash_str_add(ht, "container", sizeof("container")-1, &obj->proxy->container); + } else { + zend_hash_str_add(ht, "parent", sizeof("parent")-1, &obj->parent); + zend_hash_str_add_empty_element(ht, "container", sizeof("container")-1); + } + + zmember = zend_hash_str_add_empty_element(ht, "member", sizeof("member")-1); + ZVAL_STR(zmember, obj->proxy->member); + + *is_temp = 1; + return ht; } -#if DEBUG_PROPRO -/* we do not really care about TS when debugging */ -static int level = 1; -static const char space[] = " "; -static const char *inoutstr[] = {"< return",""," > enter"}; -static void _walk(php_property_proxy_object_t *obj TSRMLS_DC) +static ZEND_RESULT_CODE cast_obj(zval *object, zval *return_value, int type) { - if (obj) { - _walk(obj->parent TSRMLS_CC); - fprintf(stderr, ".%s", obj->proxy->member_str); + zval tmp; + + ZVAL_UNDEF(&tmp); + RETVAL_ZVAL(get_proxied_value(object, &tmp), 1, 0); + + debug_propro(0, "cast", get_propro(object), NULL, NULL, return_value); + + if (!Z_ISUNDEF_P(return_value)) { + ZVAL_DEREF(return_value); + convert_to_explicit_type_ex(return_value, type); + return SUCCESS; } + + return FAILURE; } -static void debug_propro(int inout, const char *f, zval *object, zval *offset, - zval *value TSRMLS_DC) +static zval *get_obj(zval *object, zval *return_value) { - php_property_proxy_object_t *obj; + zval tmp; - obj = zend_object_store_get_object(object TSRMLS_CC); - fprintf(stderr, "#PP %p %s %s %s ", obj, &space[sizeof(space)-level], - inoutstr[inout+1], f); + ZVAL_UNDEF(&tmp); + RETVAL_ZVAL(get_proxied_value(object, &tmp), 1, 0); + return return_value; +} - level += inout; +static void set_obj(zval *object, zval *value) { + set_proxied_value(object, value); +} - _walk(obj TSRMLS_CC); +static inline zval *get_container(zval *object, zval *tmp) +{ + php_property_proxy_object_t *obj = get_propro(object); + zval *container; - if (*f++=='d' - && *f++=='i' - && *f++=='m' - ) { - char *offset_str = "[]"; - zval *o = offset; + if (Z_ISUNDEF(obj->parent)) { + container = &obj->proxy->container; + } else { + container = get_proxied_value(&obj->parent, tmp); + } + return container; +} - if (o) { - convert_to_string_ex(&o); - offset_str = Z_STRVAL_P(o); - } +static inline void set_container(zval *object, zval *container) +{ + php_property_proxy_object_t *obj = get_propro(object); - fprintf(stderr, ".%s", offset_str); + if (Z_ISUNDEF(obj->parent)) { + if (container != &obj->proxy->container) { + zval tmp; - if (o && o != offset) { - zval_ptr_dtor(&o); + ZVAL_COPY_VALUE(&tmp, &obj->proxy->container); + ZVAL_COPY(&obj->proxy->container, container); + zval_ptr_dtor(&tmp); } + } else { + set_proxied_value(&obj->parent, container); } - if (value) { - const char *t[] = { - "NULL", - "int", - "float", - "bool", - "Array", - "Object", - "string", - "resource", - "const", - "const Array", - "callable" - }; - fprintf(stderr, " = (%s) ", t[Z_TYPE_P(value)&0xf]); - zend_print_flat_zval_r(value TSRMLS_CC); - } - - fprintf(stderr, "\n"); } -#else -#define debug_propro(l, f, obj, off, val) -#endif - -static zval *get_parent_proxied_value(zval *object TSRMLS_DC); -static zval *get_proxied_value(zval *object TSRMLS_DC); -static zval *read_dimension(zval *object, zval *offset, int type TSRMLS_DC); -static ZEND_RESULT_CODE cast_proxied_value(zval *object, zval *return_value, - int type TSRMLS_DC); -static void write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC); -static void set_proxied_value(zval **object, zval *value TSRMLS_DC); -static zval *get_parent_proxied_value(zval *object TSRMLS_DC) +static inline zval *get_container_value(zval *container, zend_string *member, zval *return_value) { - zval *value = NULL; - php_property_proxy_object_t *obj; + zval *found_value = NULL, prop_tmp; + + ZVAL_DEREF(container); + switch (Z_TYPE_P(container)) { + case IS_OBJECT: + ZVAL_UNDEF(&prop_tmp); + found_value = zend_read_property(Z_OBJCE_P(container), container, + member->val, member->len, 0, &prop_tmp); + break; + + case IS_ARRAY: + found_value = zend_symtable_find(Z_ARRVAL_P(container), member); + break; + } - obj = zend_object_store_get_object(object TSRMLS_CC); - if (obj->proxy) { - if (obj->parent) { - zval *parent; - - MAKE_STD_ZVAL(parent); - parent->type = IS_OBJECT; - parent->value.obj = obj->parent->zv; - zend_objects_store_add_ref_by_handle( - obj->parent->zv.handle TSRMLS_CC); - value = get_proxied_value(parent TSRMLS_CC); - zval_ptr_dtor(&parent); - } + if (found_value) { + RETVAL_ZVAL(found_value, 0, 0); } - return value; + return return_value; } -static zval *get_proxied_value(zval *object TSRMLS_DC) +static inline void cleanup_container(zval *object, zval *container, zend_bool separated) { - zval **hash_value, *value = NULL; - php_property_proxy_object_t *obj; - ZEND_RESULT_CODE rv; + if (separated) { + zval_ptr_dtor(container); + } +} - obj = zend_object_store_get_object(object TSRMLS_CC); - debug_propro(1, "get", object, NULL, NULL TSRMLS_CC); +static inline zend_bool separate_container(zval *object, zval *container) +{ + switch (Z_TYPE_P(container)) { + case IS_OBJECT: + return 0; + + case IS_ARRAY: + /* always duplicate for PHP-7.0 and 7.1 on travis */ + ZVAL_ARR(container, zend_array_dup(Z_ARRVAL_P(container))); + break; + + case IS_UNDEF: + array_init(container); + break; + + default: + SEPARATE_ZVAL(container); + Z_TRY_ADDREF_P(container); + convert_to_array(container); + break; + } - if (obj->proxy) { - if (obj->parent) { - zval *parent_value = get_parent_proxied_value(object TSRMLS_CC); + return 1; +} - if (parent_value && parent_value != obj->proxy->container) { - Z_ADDREF_P(parent_value); - zval_ptr_dtor(&obj->proxy->container); - obj->proxy->container = parent_value; - } - } - switch (Z_TYPE_P(obj->proxy->container)) { - case IS_OBJECT: - value = zend_read_property(Z_OBJCE_P(obj->proxy->container), - obj->proxy->container, obj->proxy->member_str, - obj->proxy->member_len, 0 TSRMLS_CC); - break; - - case IS_ARRAY: - rv = zend_symtable_find(Z_ARRVAL_P(obj->proxy->container), - obj->proxy->member_str, obj->proxy->member_len + 1, - (void *) &hash_value); - - if (SUCCESS == rv) { - value = *hash_value; - } - break; +static inline zval *set_container_value(zval *container, zend_string *member, zval *value) +{ + ZVAL_DEREF(container); + switch (Z_TYPE_P(container)) { + case IS_OBJECT: + zend_update_property(Z_OBJCE_P(container), container, + member->val, member->len, value); + break; + + case IS_ARRAY: + Z_TRY_ADDREF_P(value); + if (member) { + value = zend_symtable_update(Z_ARRVAL_P(container), member, value); + } else { + value = zend_hash_next_index_insert(Z_ARRVAL_P(container), value); } - } + break; - debug_propro(-1, "get", object, NULL, value TSRMLS_CC); + default: + ZEND_ASSERT(0); + break; + } return value; } -static ZEND_RESULT_CODE cast_proxied_value(zval *object, zval *return_value, - int type TSRMLS_DC) + +static zval *get_proxied_value(zval *object, zval *return_value) { - zval *proxied_value; + php_property_proxy_object_t *obj = get_propro(object); - if ((proxied_value = get_proxied_value(object TSRMLS_CC))) { - RETVAL_ZVAL(proxied_value, 1, 0); - if (Z_TYPE_P(proxied_value) != type) { - convert_to_explicit_type(return_value, type); - } - return SUCCESS; + debug_propro(1, "get", obj, NULL, NULL, NULL); + + if (obj->proxy) { + zval tmp, *container; + + ZVAL_UNDEF(&tmp); + container = get_container(object, &tmp); + + return_value = get_container_value(container, obj->proxy->member, return_value); } - return FAILURE; + debug_propro(-1, "get", obj, NULL, NULL, return_value); + + return return_value; } -static void set_proxied_value(zval **object, zval *value TSRMLS_DC) +static void set_proxied_value(zval *object, zval *value) { - php_property_proxy_object_t *obj; + php_property_proxy_object_t *obj = get_propro(object); - obj = zend_object_store_get_object(*object TSRMLS_CC); - debug_propro(1, "set", *object, NULL, value TSRMLS_CC); + debug_propro(1, "set", obj, NULL, NULL, value); if (obj->proxy) { - if (obj->parent) { - zval *parent_value = get_parent_proxied_value(*object TSRMLS_CC); + zval tmp, *container; + zend_bool separated; - if (parent_value && parent_value != obj->proxy->container) { - Z_ADDREF_P(parent_value); - zval_ptr_dtor(&obj->proxy->container); - obj->proxy->container = parent_value; - } - } + Z_TRY_ADDREF_P(value); - switch (Z_TYPE_P(obj->proxy->container)) { - case IS_OBJECT: - zend_update_property(Z_OBJCE_P(obj->proxy->container), - obj->proxy->container, obj->proxy->member_str, - obj->proxy->member_len, value TSRMLS_CC); - break; - - case IS_ARRAY: - Z_ADDREF_P(value); - zend_symtable_update(Z_ARRVAL_P(obj->proxy->container), - obj->proxy->member_str, obj->proxy->member_len + 1, - (void *) &value, sizeof(zval *), NULL); - break; - } + ZVAL_UNDEF(&tmp); + container = get_container(object, &tmp); + separated = separate_container(object, container); + set_container_value(container, obj->proxy->member, value); + set_container(object, container); + cleanup_container(object, container, separated); - if (obj->parent) { - zval *zparent; - MAKE_STD_ZVAL(zparent); - zparent->type = IS_OBJECT; - zparent->value.obj = obj->parent->zv; - zend_objects_store_add_ref_by_handle( - obj->parent->zv.handle TSRMLS_CC); - set_proxied_value(&zparent, obj->proxy->container TSRMLS_CC); - zval_ptr_dtor(&zparent); - } + Z_TRY_DELREF_P(value); + + debug_propro(0, "set", obj, NULL, NULL, value); } - debug_propro(-1, "set", *object, NULL, NULL TSRMLS_CC); + debug_propro(-1, "set", obj, NULL, NULL, value); } -static zval *read_dimension(zval *object, zval *offset, int type TSRMLS_DC) +static zval *read_dimension(zval *object, zval *offset, int type, zval *return_value) { - zval *value = NULL; - zval *proxied_value; - zval *o = offset; + zval *value, tmp; + zend_string *member = offset ? zval_get_string(offset) : NULL; - debug_propro(1, type == BP_VAR_R ? "dim_read" : "dim_read_ref", object, - offset, NULL TSRMLS_CC); + debug_propro(1, type == BP_VAR_R ? "dim_r" : "dim_R", + get_propro(object), NULL, offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); - convert_to_string_ex(&o); + ZVAL_UNDEF(&tmp); + value = get_proxied_value(object, &tmp); - if (BP_VAR_R == type && proxied_value) { - if (Z_TYPE_P(proxied_value) == IS_ARRAY) { - zval **hash_value; - ZEND_RESULT_CODE rv = zend_symtable_find(Z_ARRVAL_P(proxied_value), - Z_STRVAL_P(o), Z_STRLEN_P(o), (void *) &hash_value); + if (type == BP_VAR_R || type == BP_VAR_IS) { + ZEND_ASSERT(member); - if (SUCCESS == rv) { - Z_ADDREF_PP(hash_value); - value = *hash_value; - } + if (!Z_ISUNDEF_P(value)) { + zval tmp; + + ZVAL_UNDEF(&tmp); + RETVAL_ZVAL(get_container_value(value, member, &tmp), 1, 0); } } else { php_property_proxy_t *proxy; php_property_proxy_object_t *proxy_obj; - if (proxied_value) { - convert_to_array(proxied_value); - Z_ADDREF_P(proxied_value); - } else { - MAKE_STD_ZVAL(proxied_value); - array_init(proxied_value); - set_proxied_value(&object, proxied_value TSRMLS_CC); + if (Z_ISUNDEF_P(value)) { + ZVAL_NULL(value); + } + + if (!member) { + if (Z_TYPE_P(value) == IS_ARRAY) { + member = zend_long_to_str(zend_hash_next_free_element( + Z_ARRVAL_P(value))); + } else if (Z_TYPE_P(value) != IS_OBJECT){ + member = zend_long_to_str(0); + } } - proxy = php_property_proxy_init(proxied_value, Z_STRVAL_P(o), - Z_STRLEN_P(o) TSRMLS_CC); - zval_ptr_dtor(&proxied_value); - MAKE_STD_ZVAL(value); - Z_SET_REFCOUNT_P(value, 0); - value->type = IS_OBJECT; - value->value.obj = php_property_proxy_object_new_ex( - php_property_proxy_get_class_entry(), proxy, - &proxy_obj TSRMLS_CC); - proxy_obj->parent = zend_object_store_get_object(object TSRMLS_CC); - zend_objects_store_add_ref_by_handle( - proxy_obj->parent->zv.handle TSRMLS_CC); + proxy = php_property_proxy_init(NULL, member); + proxy_obj = php_property_proxy_object_new_ex(NULL, proxy); + ZVAL_COPY(&proxy_obj->parent, object); + RETVAL_OBJ(&proxy_obj->zo); + + debug_propro(0, "dim_R pp", get_propro(object), NULL, offset, return_value); } - if (o && o != offset) { - zval_ptr_dtor(&o); + + if (member) { + zend_string_release(member); } - debug_propro(-1, type == BP_VAR_R ? "dim_read" : "dim_read_ref", object, - offset, value TSRMLS_CC); + debug_propro(-1, type == BP_VAR_R ? "dim_r" : "dim_R", + get_propro(object), NULL, offset, return_value); - return value; + return return_value; } -static int has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) +static int has_dimension(zval *object, zval *offset, int check_empty) { - zval *proxied_value; + zval *value, tmp; int exists = 0; - debug_propro(1, "dim_exists", object, offset, NULL TSRMLS_CC); + debug_propro(1, "dim_e", get_propro(object), NULL, offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); - if (!proxied_value) { - exists = 0; - } else { - zval *o = offset; + ZVAL_UNDEF(&tmp); + value = get_proxied_value(object, &tmp); - convert_to_string_ex(&o); + if (!Z_ISUNDEF_P(value)) { + zend_string *zs = zval_get_string(offset); - if (Z_TYPE_P(proxied_value) == IS_ARRAY) { - zval **zentry; - ZEND_RESULT_CODE rv = zend_symtable_find(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), Z_STRLEN_P(o) + 1, (void *) &zentry); + ZVAL_DEREF(value); + if (Z_TYPE_P(value) == IS_ARRAY) { + zval *zentry = zend_symtable_find(Z_ARRVAL_P(value), zs); - if (SUCCESS != rv) { - exists = 0; - } else { + if (zentry) { if (check_empty) { - exists = Z_TYPE_PP(zentry) != IS_NULL; + exists = !Z_ISNULL_P(zentry); } else { exists = 1; } } } - if (o != offset) { - zval_ptr_dtor(&o); - } + zend_string_release(zs); } - debug_propro(-1, "dim_exists", object, offset, NULL TSRMLS_CC); + debug_propro(-1, "dim_e", get_propro(object), NULL, offset, NULL); return exists; } -static void write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) +static void write_dimension(zval *object, zval *offset, zval *input_value) { - zval *proxied_value, *o = offset; - - debug_propro(1, "dim_write", object, offset, value TSRMLS_CC); + zval *array, tmp; + zend_string *zs = NULL; + zend_bool separated; - proxied_value = get_proxied_value(object TSRMLS_CC); + debug_propro(1, "dim_w", get_propro(object), NULL, offset, input_value); - if (proxied_value) { - convert_to_array(proxied_value); - Z_ADDREF_P(proxied_value); - } else { - MAKE_STD_ZVAL(proxied_value); - array_init(proxied_value); + if (offset) { + zs = zval_get_string(offset); } - if (Z_REFCOUNT_P(value) > 1) { - SEPARATE_ZVAL(&value); - } - Z_ADDREF_P(value); - - if (o) { - convert_to_string_ex(&o); - zend_symtable_update(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), - Z_STRLEN_P(o) + 1, (void *) &value, sizeof(zval *), NULL); - } else { - zend_hash_next_index_insert(Z_ARRVAL_P(proxied_value), (void *) &value, - sizeof(zval *), NULL); - } + ZVAL_UNDEF(&tmp); + array = get_proxied_value(object, &tmp); + separated = separate_container(object, array); + set_container_value(array, zs, input_value); + set_proxied_value(object, array); + cleanup_container(object, array, separated); - if (o && o != offset) { - zval_ptr_dtor(&o); + if (zs) { + zend_string_release(zs); } - set_proxied_value(&object, proxied_value TSRMLS_CC); - - debug_propro(-1, "dim_write", object, offset, proxied_value TSRMLS_CC); - - zval_ptr_dtor(&proxied_value); + debug_propro(-1, "dim_w", get_propro(object), NULL, offset, input_value); } -static void unset_dimension(zval *object, zval *offset TSRMLS_DC) +static void unset_dimension(zval *object, zval *offset) { - zval *proxied_value; + zval *array, *value, tmp; - debug_propro(1, "dim_unset", object, offset, NULL TSRMLS_CC); + debug_propro(1, "dim_u", get_propro(object), NULL, offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); + ZVAL_UNDEF(&tmp); + value = get_proxied_value(object, &tmp); + array = value; + ZVAL_DEREF(array); - if (proxied_value && Z_TYPE_P(proxied_value) == IS_ARRAY) { - zval *o = offset; - ZEND_RESULT_CODE rv; + if (Z_TYPE_P(array) == IS_ARRAY) { + zend_string *o = zval_get_string(offset); - convert_to_string_ex(&o); - rv = zend_symtable_del(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), - Z_STRLEN_P(o) + 1); + SEPARATE_ARRAY(array); + zend_symtable_del(Z_ARRVAL_P(array), o); - if (SUCCESS == rv) { - set_proxied_value(&object, proxied_value TSRMLS_CC); - } + set_proxied_value(object, value); - if (o != offset) { - zval_ptr_dtor(&o); - } + zend_string_release(o); } - debug_propro(-1, "dim_unset", object, offset, proxied_value TSRMLS_CC); + debug_propro(-1, "dim_u", get_propro(object), NULL, offset, NULL); } ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct, 0, 0, 2) - ZEND_ARG_INFO(1, object) + ZEND_ARG_INFO(0, object) ZEND_ARG_INFO(0, member) ZEND_ARG_OBJ_INFO(0, parent, php\\PropertyProxy, 1) ZEND_END_ARG_INFO(); static PHP_METHOD(propro, __construct) { zend_error_handling zeh; - zval *container, *parent = NULL; - char *member_str; - int member_len; + zval *reference, *parent = NULL; + zend_string *member; - zend_replace_error_handling(EH_THROW, NULL, &zeh TSRMLS_CC); - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|O!", - &container, &member_str, &member_len, &parent, + zend_replace_error_handling(EH_THROW, NULL, &zeh); + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "o!S|O!", + &reference, &member, &parent, php_property_proxy_class_entry)) { php_property_proxy_object_t *obj; - obj = zend_object_store_get_object(getThis() TSRMLS_CC); - obj->proxy = php_property_proxy_init(container, member_str, - member_len TSRMLS_CC); + obj = get_propro(getThis()); + if (parent) { - zend_objects_store_add_ref(parent TSRMLS_CC); - obj->parent = zend_object_store_get_object(parent TSRMLS_CC); + ZVAL_COPY(&obj->parent, parent); + obj->proxy = php_property_proxy_init(NULL, member); + } else if (reference) { + zval *container = reference; + obj->proxy = php_property_proxy_init(container, member); + } else { + php_error(E_WARNING, "Either object or parent must be set"); } } - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_restore_error_handling(&zeh); } static const zend_function_entry php_property_proxy_method_entry[] = { @@ -531,17 +669,19 @@ static PHP_MINIT_FUNCTION(propro) INIT_NS_CLASS_ENTRY(ce, "php", "PropertyProxy", php_property_proxy_method_entry); - php_property_proxy_class_entry = zend_register_internal_class_ex(&ce, NULL, - NULL TSRMLS_CC); - php_property_proxy_class_entry->create_object = - php_property_proxy_object_new; - php_property_proxy_class_entry->ce_flags |= ZEND_ACC_FINAL_CLASS; + php_property_proxy_class_entry = zend_register_internal_class(&ce); + php_property_proxy_class_entry->create_object = php_property_proxy_object_new; + php_property_proxy_class_entry->ce_flags |= ZEND_ACC_FINAL; memcpy(&php_property_proxy_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_property_proxy_object_handlers.set = set_proxied_value; - php_property_proxy_object_handlers.get = get_proxied_value; - php_property_proxy_object_handlers.cast_object = cast_proxied_value; + php_property_proxy_object_handlers.offset = XtOffsetOf(php_property_proxy_object_t, zo); + php_property_proxy_object_handlers.free_obj = destroy_obj; + php_property_proxy_object_handlers.get_gc = get_gc; + php_property_proxy_object_handlers.get_debug_info = get_debug_info; + php_property_proxy_object_handlers.set = set_obj; + php_property_proxy_object_handlers.get = get_obj; + php_property_proxy_object_handlers.cast_object = cast_obj; php_property_proxy_object_handlers.read_dimension = read_dimension; php_property_proxy_object_handlers.write_dimension = write_dimension; php_property_proxy_object_handlers.has_dimension = has_dimension;