From: Michael Wallner Date: Tue, 29 Sep 2015 15:03:31 +0000 (+0200) Subject: Merge branch 'R_1_0' X-Git-Tag: release-2.0.0RC1~12 X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-propro;a=commitdiff_plain;h=ac900495e2e232c7a2f3e9f226421a4f457ce7b9;hp=0bdcf34d8c73b4a4b12af15f1629333894e4243d Merge branch 'R_1_0' --- diff --git a/README.md b/README.md index 88242d9..333d2c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ext-propro -[![Build Status](https://travis-ci.org/m6w6/ext-propro.svg?branch=R_1_0)](https://travis-ci.org/m6w6/ext-propro) +[![Build Status](https://travis-ci.org/m6w6/ext-propro.svg?branch=master)](https://travis-ci.org/m6w6/ext-propro) Property Proxy diff --git a/package.xml b/package.xml index 60f0d38..b4118df 100644 --- a/package.xml +++ b/package.xml @@ -21,8 +21,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> 2013-12-05 - 1.0.1 - 1.0.0 + 2.0.0-dev + 2.0.0 stable @@ -30,7 +30,6 @@ http://pear.php.net/dtd/package-2.0.xsd"> BSD-2-Clause @@ -50,15 +49,14 @@ http://pear.php.net/dtd/package-2.0.xsd"> + - 5.3.0 - 7.0.0 - 7.0.0 + 7.0.0 1.4.0 diff --git a/php_propro.c b/php_propro.c index 0599b9a..c92d6d4 100644 --- a/php_propro.c +++ b/php_propro.c @@ -18,32 +18,24 @@ #include #include -#include "php_propro.h" - -#if PHP_VERSION_ID < 50500 -typedef enum { - SUCCESS = 0, - FAILURE = -1 -} ZEND_RESULT_CODE; -#endif +#include "php_propro_api.h" #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*)) -#endif +static inline zval *get_referenced_zval(zval *ref) +{ + while (Z_ISREF_P(ref)) { + ref = Z_REFVAL_P(ref); + } + return ref; +} -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)); - Z_ADDREF_P(container); - proxy->container = container; - proxy->member_str = estrndup(member_str, member_len); - proxy->member_len = member_len; + ZVAL_COPY(&proxy->container, get_referenced_zval(container)); + proxy->member = zend_string_copy(member); return proxy; } @@ -52,7 +44,7 @@ void php_property_proxy_free(php_property_proxy_t **proxy) { if (*proxy) { zval_ptr_dtor(&(*proxy)->container); - efree((*proxy)->member_str); + zend_string_release((*proxy)->member); efree(*proxy); *proxy = NULL; } @@ -66,81 +58,41 @@ 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) -{ - return php_property_proxy_object_new_ex(ce, NULL, NULL TSRMLS_CC); -} - -static void php_property_proxy_object_free(void *object TSRMLS_DC) -{ - php_property_proxy_object_t *o = object; - -#if DEBUG_PROPRO - fprintf(stderr, "#PP %p free\n", o); -#endif - - 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; - } - zend_object_std_dtor((zend_object *) o TSRMLS_CC); - efree(o); -} - -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) -{ - php_property_proxy_object_t *o; - - o = ecalloc(1, sizeof(*o)); - zend_object_std_init((zend_object *) o, ce TSRMLS_CC); - object_properties_init((zend_object *) o, ce); - - if (ptr) { - *ptr = o; - } - o->proxy = proxy; - - 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; - -#if DEBUG_PROPRO - fprintf(stderr, "#PP %p init\n", o); -#endif - - return o->zv; -} +static inline php_property_proxy_object_t *get_propro(zval *object); +static zval *get_parent_proxied_value(zval *object, zval *return_value); +static zval *get_proxied_value(zval *object, zval *return_value); +static zval *read_dimension(zval *object, zval *offset, int type, zval *return_value); +static ZEND_RESULT_CODE cast_proxied_value(zval *object, zval *return_value, int type); +static void write_dimension(zval *object, zval *offset, zval *value); +static void set_proxied_value(zval *object, zval *value); #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 const char *inoutstr[] = {"< return","="," > enter"}; + +static void _walk(php_property_proxy_object_t *obj) { if (obj) { - _walk(obj->parent TSRMLS_CC); - fprintf(stderr, ".%s", obj->proxy->member_str); + if (!Z_ISUNDEF(obj->parent)) { + _walk(get_propro(&obj->parent)); + } + if (obj->proxy) { + fprintf(stderr, ".%s", obj->proxy->member->val); + } } } -static void debug_propro(int inout, const char *f, zval *object, zval *offset, - zval *value TSRMLS_DC) +static void debug_propro(int inout, const char *f, + php_property_proxy_object_t *obj, zval *offset, zval *value TSRMLS_DC) { - php_property_proxy_object_t *obj; - - 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); level += inout; - _walk(obj TSRMLS_CC); + _walk(obj); if (*f++=='d' && *f++=='i' @@ -150,32 +102,41 @@ static void debug_propro(int inout, const char *f, zval *object, zval *offset, zval *o = offset; if (o) { - convert_to_string_ex(&o); + convert_to_string_ex(o); offset_str = Z_STRVAL_P(o); } fprintf(stderr, ".%s", offset_str); if (o && o != offset) { - zval_ptr_dtor(&o); + zval_ptr_dtor(o); } } - if (value) { + if (value && !Z_ISUNDEF_P(value)) { const char *t[] = { + "UNDEF", "NULL", + "FALSE", + "TRUE", "int", "float", - "bool", + "string", "Array", "Object", - "string", "resource", - "const", - "const Array", - "callable" + "reference", + "constant", + "constant AST", + "_BOOL", + "callable", + "indirect", + "---", + "pointer" }; fprintf(stderr, " = (%s) ", t[Z_TYPE_P(value)&0xf]); - zend_print_flat_zval_r(value TSRMLS_CC); + if (!Z_ISUNDEF_P(value) && Z_TYPE_P(value) != IS_INDIRECT) { + zend_print_flat_zval_r(value TSRMLS_CC); + } } fprintf(stderr, "\n"); @@ -184,310 +145,353 @@ static void debug_propro(int inout, const char *f, zval *object, zval *offset, #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); +php_property_proxy_object_t *php_property_proxy_object_new_ex( + zend_class_entry *ce, php_property_proxy_t *proxy) +{ + 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; + + debug_propro(0, "init", o, NULL, NULL); + + return o; +} + +zend_object *php_property_proxy_object_new(zend_class_entry *ce) +{ + return &php_property_proxy_object_new_ex(ce, NULL)->zo; +} + +static void destroy_obj(zend_object *object) +{ + php_property_proxy_object_t *o = PHP_PROPRO_PTR(object); + + debug_propro(0, "dtor", o, NULL, NULL); + + if (o->proxy) { + php_property_proxy_free(&o->proxy); + } + if (!Z_ISUNDEF(o->parent)) { + zval_ptr_dtor(&o->parent); + ZVAL_UNDEF(&o->parent); + } + zend_object_std_dtor(object); +} + +static inline php_property_proxy_object_t *get_propro(zval *object) +{ + object = get_referenced_zval(object); + switch (Z_TYPE_P(object)) { + case IS_OBJECT: + break; -static zval *get_parent_proxied_value(zval *object TSRMLS_DC) + EMPTY_SWITCH_DEFAULT_CASE(); + } + return PHP_PROPRO_PTR(Z_OBJ_P(object)); +} + +static inline zend_bool got_value(zval *container, zval *value) +{ + zval identical; + + if (!Z_ISUNDEF_P(value)) { + if (SUCCESS == is_identical_function(&identical, value, container)) { + if (Z_TYPE(identical) != IS_TRUE) { + return 1; + } + } + } + + return 0; +} + +static zval *get_parent_proxied_value(zval *object, zval *return_value) { - zval *value = NULL; php_property_proxy_object_t *obj; - obj = zend_object_store_get_object(object TSRMLS_CC); + obj = get_propro(object); + debug_propro(1, "parent_get", obj, NULL, NULL); + 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 (!Z_ISUNDEF(obj->parent)) { + get_proxied_value(&obj->parent, return_value); } } - return value; + debug_propro(-1, "parent_get", obj, NULL, return_value); + + return return_value; } -static zval *get_proxied_value(zval *object TSRMLS_DC) +static zval *get_proxied_value(zval *object, zval *return_value) { - zval **hash_value, *value = NULL; + zval *hash_value, *ref, prop_tmp; php_property_proxy_object_t *obj; - ZEND_RESULT_CODE rv; - obj = zend_object_store_get_object(object TSRMLS_CC); - debug_propro(1, "get", object, NULL, NULL TSRMLS_CC); + obj = get_propro(object); + debug_propro(1, "get", obj, NULL, NULL); if (obj->proxy) { - if (obj->parent) { - zval *parent_value = get_parent_proxied_value(object TSRMLS_CC); + if (!Z_ISUNDEF(obj->parent)) { + zval parent_value; - if (parent_value && parent_value != obj->proxy->container) { - Z_ADDREF_P(parent_value); + ZVAL_UNDEF(&parent_value); + get_parent_proxied_value(object, &parent_value); + + if (got_value(&obj->proxy->container, &parent_value)) { zval_ptr_dtor(&obj->proxy->container); - obj->proxy->container = parent_value; + ZVAL_COPY(&obj->proxy->container, &parent_value); } } - switch (Z_TYPE_P(obj->proxy->container)) { + + ref = get_referenced_zval(&obj->proxy->container); + + switch (Z_TYPE_P(ref)) { 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); + RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(ref), ref, + obj->proxy->member->val, obj->proxy->member->len, 0, &prop_tmp), + 0, 0); 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); + hash_value = zend_symtable_find(Z_ARRVAL_P(ref), obj->proxy->member); - if (SUCCESS == rv) { - value = *hash_value; + if (hash_value) { + RETVAL_ZVAL(hash_value, 0, 0); } break; } } - debug_propro(-1, "get", object, NULL, value TSRMLS_CC); + debug_propro(-1, "get", obj, NULL, return_value); - return value; + return return_value; } static ZEND_RESULT_CODE cast_proxied_value(zval *object, zval *return_value, - int type TSRMLS_DC) + int type) { - zval *proxied_value; + get_proxied_value(object, return_value); - 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); - } + debug_propro(0, "cast", get_propro(object), NULL, return_value); + + if (!Z_ISUNDEF_P(return_value)) { + convert_to_explicit_type_ex(return_value, type); return SUCCESS; } return FAILURE; } -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; + zval *ref; - obj = zend_object_store_get_object(*object TSRMLS_CC); - debug_propro(1, "set", *object, NULL, value TSRMLS_CC); + obj = get_propro(object); + debug_propro(1, "set", obj, NULL, value TSRMLS_CC); if (obj->proxy) { - if (obj->parent) { - zval *parent_value = get_parent_proxied_value(*object TSRMLS_CC); + if (!Z_ISUNDEF(obj->parent)) { + zval parent_value; + + ZVAL_UNDEF(&parent_value); + get_parent_proxied_value(object, &parent_value); - if (parent_value && parent_value != obj->proxy->container) { - Z_ADDREF_P(parent_value); + if (got_value(&obj->proxy->container, &parent_value)) { zval_ptr_dtor(&obj->proxy->container); - obj->proxy->container = parent_value; + ZVAL_COPY(&obj->proxy->container, &parent_value); } } - switch (Z_TYPE_P(obj->proxy->container)) { + ref = get_referenced_zval(&obj->proxy->container); + + switch (Z_TYPE_P(ref)) { 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); + zend_update_property(Z_OBJCE_P(ref), ref, obj->proxy->member->val, + obj->proxy->member->len, value); break; + default: + convert_to_array(ref); + /* no 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); + Z_TRY_ADDREF_P(value); + zend_symtable_update(Z_ARRVAL_P(ref), obj->proxy->member, value); break; } - 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); + if (!Z_ISUNDEF(obj->parent)) { + set_proxied_value(&obj->parent, &obj->proxy->container); } } - debug_propro(-1, "set", *object, NULL, NULL TSRMLS_CC); + debug_propro(-1, "set", obj, NULL, NULL); } -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 proxied_value; + 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_read" : "dim_read_ref", + get_propro(object), offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); - convert_to_string_ex(&o); + ZVAL_UNDEF(&proxied_value); + get_proxied_value(object, &proxied_value); - 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 (BP_VAR_R == type && member && !Z_ISUNDEF(proxied_value)) { + if (Z_TYPE(proxied_value) == IS_ARRAY) { + zval *hash_value = zend_symtable_find(Z_ARRVAL(proxied_value), + member); - if (SUCCESS == rv) { - Z_ADDREF_PP(hash_value); - value = *hash_value; + if (hash_value) { + RETVAL_ZVAL(hash_value, 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); + if (!Z_ISUNDEF(proxied_value)) { + convert_to_array(&proxied_value); + Z_ADDREF(proxied_value); } else { - MAKE_STD_ZVAL(proxied_value); - array_init(proxied_value); - set_proxied_value(&object, proxied_value TSRMLS_CC); + array_init(&proxied_value); + set_proxied_value(object, &proxied_value); + } + + if (!member) { + member = zend_long_to_str(zend_hash_next_free_element( + Z_ARRVAL(proxied_value))); } - proxy = php_property_proxy_init(proxied_value, Z_STRVAL_P(o), - Z_STRLEN_P(o) TSRMLS_CC); + proxy = php_property_proxy_init(&proxied_value, member); 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_obj = php_property_proxy_object_new_ex(NULL, proxy); + ZVAL_COPY(&proxy_obj->parent, object); + RETVAL_OBJ(&proxy_obj->zo); } - 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_read" : "dim_read_ref", + get_propro(object), 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 proxied_value; int exists = 0; - debug_propro(1, "dim_exists", object, offset, NULL TSRMLS_CC); + debug_propro(1, "dim_exists", get_propro(object), offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); - if (!proxied_value) { + ZVAL_UNDEF(&proxied_value); + get_proxied_value(object, &proxied_value); + if (Z_ISUNDEF(proxied_value)) { exists = 0; } else { - zval *o = offset; + zend_string *zs = zval_get_string(offset); - convert_to_string_ex(&o); + if (Z_TYPE(proxied_value) == IS_ARRAY) { + zval *zentry = zend_symtable_find(Z_ARRVAL(proxied_value), zs); - 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); - - if (SUCCESS != rv) { + if (!zentry) { exists = 0; } else { 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_exists", get_propro(object), 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 *value) { - zval *proxied_value, *o = offset; + zval proxied_value; - debug_propro(1, "dim_write", object, offset, value TSRMLS_CC); + debug_propro(1, "dim_write", get_propro(object), offset, value); - proxied_value = get_proxied_value(object TSRMLS_CC); + ZVAL_UNDEF(&proxied_value); + get_proxied_value(object, &proxied_value); - if (proxied_value) { - convert_to_array(proxied_value); - Z_ADDREF_P(proxied_value); + if (!Z_ISUNDEF(proxied_value)) { + if (Z_TYPE(proxied_value) == IS_ARRAY) { + Z_ADDREF(proxied_value); + } else { + convert_to_array(&proxied_value); + } } else { - MAKE_STD_ZVAL(proxied_value); - array_init(proxied_value); + array_init(&proxied_value); } - if (Z_REFCOUNT_P(value) > 1) { - SEPARATE_ZVAL(&value); - } - Z_ADDREF_P(value); + SEPARATE_ZVAL(value); + Z_TRY_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); + if (offset) { + zend_string *zs = zval_get_string(offset); + zend_symtable_update(Z_ARRVAL(proxied_value), zs, value); + zend_string_release(zs); } else { - zend_hash_next_index_insert(Z_ARRVAL_P(proxied_value), (void *) &value, - sizeof(zval *), NULL); + zend_hash_next_index_insert(Z_ARRVAL(proxied_value), value); } - if (o && o != offset) { - zval_ptr_dtor(&o); - } + set_proxied_value(object, &proxied_value); - set_proxied_value(&object, proxied_value TSRMLS_CC); - - debug_propro(-1, "dim_write", object, offset, proxied_value TSRMLS_CC); + debug_propro(-1, "dim_write", get_propro(object), offset, &proxied_value); zval_ptr_dtor(&proxied_value); } -static void unset_dimension(zval *object, zval *offset TSRMLS_DC) +static void unset_dimension(zval *object, zval *offset) { - zval *proxied_value; + zval proxied_value; - debug_propro(1, "dim_unset", object, offset, NULL TSRMLS_CC); + debug_propro(1, "dim_unset", get_propro(object), offset, NULL); - proxied_value = get_proxied_value(object TSRMLS_CC); + ZVAL_UNDEF(&proxied_value); + get_proxied_value(object, &proxied_value); - if (proxied_value && Z_TYPE_P(proxied_value) == IS_ARRAY) { + if (Z_TYPE(proxied_value) == IS_ARRAY) { zval *o = offset; ZEND_RESULT_CODE rv; - convert_to_string_ex(&o); - rv = zend_symtable_del(Z_ARRVAL_P(proxied_value), Z_STRVAL_P(o), - Z_STRLEN_P(o) + 1); - + convert_to_string_ex(o); + rv = zend_symtable_del(Z_ARRVAL(proxied_value), Z_STR_P(o)); if (SUCCESS == rv) { - set_proxied_value(&object, proxied_value TSRMLS_CC); + set_proxied_value(object, &proxied_value); } if (o != offset) { - zval_ptr_dtor(&o); + zval_ptr_dtor(o); } } - debug_propro(-1, "dim_unset", object, offset, proxied_value TSRMLS_CC); + debug_propro(-1, "dim_unset", get_propro(object), offset, &proxied_value); } ZEND_BEGIN_ARG_INFO_EX(ai_propro_construct, 0, 0, 2) @@ -498,24 +502,29 @@ ZEND_END_ARG_INFO(); static PHP_METHOD(propro, __construct) { zend_error_handling zeh; zval *container, *parent = NULL; - char *member_str; - int member_len; + 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(), "zS|O!", + &container, &member, &parent, php_property_proxy_class_entry)) { php_property_proxy_object_t *obj; + zval *ref = get_referenced_zval(container); - obj = zend_object_store_get_object(getThis() TSRMLS_CC); - obj->proxy = php_property_proxy_init(container, member_str, - member_len TSRMLS_CC); + switch (Z_TYPE_P(ref)) { + case IS_OBJECT: + case IS_ARRAY: + break; + default: + convert_to_array(ref); + } + obj = get_propro(getThis()); + obj->proxy = php_property_proxy_init(container, member); 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); } } - zend_restore_error_handling(&zeh TSRMLS_CC); + zend_restore_error_handling(&zeh); } static const zend_function_entry php_property_proxy_method_entry[] = { @@ -529,14 +538,14 @@ 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.offset = XtOffsetOf(php_property_proxy_object_t, zo); + php_property_proxy_object_handlers.free_obj = destroy_obj; 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; diff --git a/php_propro.h b/php_propro.h index 7d7acd4..6752091 100644 --- a/php_propro.h +++ b/php_propro.h @@ -16,7 +16,7 @@ extern zend_module_entry propro_module_entry; #define phpext_propro_ptr &propro_module_entry -#define PHP_PROPRO_VERSION "1.0.1" +#define PHP_PROPRO_VERSION "2.0.0dev" #ifdef PHP_WIN32 # define PHP_PROPRO_API __declspec(dllexport) @@ -30,7 +30,7 @@ extern zend_module_entry propro_module_entry; # include #endif -#include "php_propro_api.h" +#define PHP_PROPRO_PTR(zo) (void*)(((char*)(zo))-(zo)->handlers->offset) #endif /* PHP_PROPRO_H */ diff --git a/php_propro_api.h b/php_propro_api.h index a2add4f..d82055f 100644 --- a/php_propro_api.h +++ b/php_propro_api.h @@ -22,11 +22,9 @@ */ struct php_property_proxy { /** The container holding the property */ - zval *container; + zval container; /** The name of the proxied property */ - char *member_str; - /** The length of the name */ - size_t member_len; + zend_string *member; }; typedef struct php_property_proxy php_property_proxy_t; @@ -38,52 +36,38 @@ typedef struct php_property_proxy php_property_proxy_t; * * Example: * ~~~~~~~~~~{.c} - * static zval *my_read_prop(zval *object, zval *member, int type, zend_literal *key TSRMLS_DC) + * static zval *my_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp) * { - * my_object_t *obj = zend_object_store_get_object(object TSRMLS_CC); - * my_prophandler_t *handler; - * zval *return_value, *copy = my_cast(IS_STRING, member); + * zval *return_value; + * zend_string *member_name = zval_get_string(member); + * my_prophandler_t *handler = my_get_prophandler(member_name); * - * if (SUCCESS == my_get_prophandler(Z_STRVAL_P(copy), Z_STRLEN_P(copy), &handler)) { - * ALLOC_ZVAL(return_value); - * Z_SET_REFCOUNT_P(return_value, 0); - * Z_UNSET_ISREF_P(return_value); + * if (!handler || type == BP_VAR_R || type == BP_VAR_IS) { + * return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp); * - * if (type == BP_VAR_R) { - * handler->read(obj, return_value TSRMLS_CC); - * } else { - * // - * // This is the interesting part - * // - * php_property_proxy_t *proxy; - * zend_object_value proxy_ov; - * zend_class_entry *proxy_ce; + * if (handler) { + * handler->read(object, tmp); * - * proxy = php_property_proxy_init(object, Z_STRVAL_P(copy), Z_STRLEN_P(copy) TSRMLS_CC); - * proxy_ce = php_property_proxy_get_class_entry(); - * proxy_ov = php_property_proxy_object_new_ex(proxy_ce, proxy, NULL TSRMLS_CC); - * RETVAL_OBJVAL(proxy_ov, 0); - * } - * } else { - * zend_object_handlers *oh = zend_get_std_object_handlers(); - * return_value = oh->read_property(object, member, type, key TSRMLS_CC); - * } + * zval_ptr_dtor(return_value); + * ZVAL_COPY_VALUE(return_value, tmp); + * } + * } else { + * return_value = php_property_proxy_zval(object, member_name); + * } * - * zval_ptr_dtor(©); + * zend_string_release(member_name); * - * return return_value; + * return return_value; * } * ~~~~~~~~~~ */ struct php_property_proxy_object { - /** The std zend_object */ - zend_object zo; - /** The object value for easy zval creation */ - zend_object_value zv; /** The actual property proxy */ php_property_proxy_t *proxy; - /** A reference to any parent property proxy object */ - struct php_property_proxy_object *parent; + /** Any parent property proxy object */ + zval parent; + /** The std zend_object */ + zend_object zo; }; typedef struct php_property_proxy_object php_property_proxy_object_t; @@ -94,12 +78,11 @@ typedef struct php_property_proxy_object php_property_proxy_object_t; * proxied property with name \a member_str of \a container. * * @param container the container holding the property - * @param member_str the name of the proxied property - * @param member_len the length of the name + * @param member the name of the proxied property * @return a new property proxy */ PHP_PROPRO_API php_property_proxy_t *php_property_proxy_init(zval *container, - const char *member_str, size_t member_len TSRMLS_DC); + zend_string *member); /** * Destroy and free a property proxy. @@ -119,21 +102,18 @@ PHP_PROPRO_API zend_class_entry *php_property_proxy_get_class_entry(void); /** * Instantiate a new php\\PropertyProxy * @param ce the property proxy or derived class entry - * @return the zval object value + * @return the zend object */ -PHP_PROPRO_API zend_object_value php_property_proxy_object_new( - zend_class_entry *ce TSRMLS_DC); +PHP_PROPRO_API zend_object *php_property_proxy_object_new(zend_class_entry *ce); /** * Instantiate a new php\\PropertyProxy with \a proxy * @param ce the property proxy or derived class entry * @param proxy the internal property proxy - * @param ptr a pointer to store the resulting property proxy object - * @return the zval object value + * @return the property proxy */ -PHP_PROPRO_API 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); +PHP_PROPRO_API php_property_proxy_object_t *php_property_proxy_object_new_ex( + zend_class_entry *ce, php_property_proxy_t *proxy); #endif /* PHP_PROPRO_API_H */ diff --git a/tests/001.phpt b/tests/001.phpt index 45b07db..d085758 100644 --- a/tests/001.phpt +++ b/tests/001.phpt @@ -22,7 +22,9 @@ $a = $c->anon; var_dump($c); +echo "set\n"; $a = 123; +echo "get\n"; echo $a,"\n"; $p["foo"] = 123; @@ -40,6 +42,8 @@ object(c)#%d (2) { ["anon":"c":private]=> NULL } +set +get 123 object(c)#%d (2) { ["prop":"c":private]=> diff --git a/tests/003.phpt b/tests/003.phpt new file mode 100644 index 0000000..886e220 --- /dev/null +++ b/tests/003.phpt @@ -0,0 +1,41 @@ +--TEST-- +property proxy +--SKIPIF-- + +--FILE-- +ref; +$r = 1; +var_dump($t); +$t->ref[] = 2; +var_dump($t); +?> +===DONE=== +--EXPECTF-- +Test +object(t)#%d (1) { + ["ref":"t":private]=> + int(1) +} +object(t)#%d (1) { + ["ref":"t":private]=> + array(2) { + [0]=> + int(1) + [1]=> + int(2) + } +} +===DONE=== \ No newline at end of file