[config.w32] Warn that propro was discontinued
[m6w6/ext-propro] / src / php_propro_api.c
index 16cca62e54c3a8fb7755d86e3877f01c99b60288..631f707c3a9a77d9944c77240851a0df6ff4489e 100644 (file)
@@ -105,30 +105,16 @@ static void debug_propro(int inout, const char *f,
 
        if (proxy) {
                ZVAL_UNDEF(&tmp);
-               if (obj) {
-                       if (Z_ISUNDEF(obj->parent)) {
-                               container = &obj->proxy->container;
-                       } else {
-                               zval parent_tmp, *parent_container;
-                               php_property_proxy_object_t *parent_obj = get_propro(&obj->parent);
-
-                               ZVAL_UNDEF(&parent_tmp);
-                               parent_container = get_container(&obj->parent, &parent_tmp);
-                               container = get_container_value(parent_container, parent_obj->proxy->member, &tmp);
-                       }
+               if (!obj) {
+                       container = &proxy->container;
+               } else if (Z_ISUNDEF(obj->parent)) {
+                       container = &obj->proxy->container;
                }
-               fprintf(stderr, " container= %-14p < %-10s rc=%-11d ",
+               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);
-               if (Z_ISREF_P(container)) {
-                       zval *ref = Z_REFVAL_P(container);
-                       fprintf(stderr, " %-12s %p rc=% 2d",
-                                       _type(ref),
-                                       ref->value.counted,
-                                       Z_REFCOUNTED_P(ref) ? Z_REFCOUNT_P(ref) : -1);
-               }
-               fprintf(stderr, "> ");
+                               Z_REFCOUNTED_P(container) ? Z_REFCOUNT_P(container) : 0,
+                               Z_ISREF_P(container) ? "(ref)  ":"(noref)");
        }
 
        width = _walk(obj);
@@ -156,11 +142,11 @@ static void debug_propro(int inout, const char *f,
                if (Z_ISUNDEF_P(value)) {
                        fprintf(stderr, " = UNDEF");
                } else {
-                       fprintf(stderr, " = %-14p < %-10s rc=%-11d %3s> ",
+                       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" : "");
+                                       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);
                        }
@@ -182,14 +168,12 @@ php_property_proxy_t *php_property_proxy_init(zval *container, zend_string *memb
        ZVAL_STR_COPY(&offset, member);
 #endif
 
-       debug_propro(1, "init", NULL, proxy, &offset, NULL);
-
        if (container) {
                ZVAL_COPY(&proxy->container, container);
        }
        proxy->member = zend_string_copy(member);
 
-       debug_propro(-1, "init", NULL, proxy, &offset, NULL);
+       debug_propro(0, "init", NULL, proxy, &offset, NULL);
 
 #if DEBUG_PROPRO
        zval_dtor(&offset);
@@ -204,13 +188,14 @@ void php_property_proxy_free(php_property_proxy_t **proxy)
        zval offset;
 
        ZVAL_STR_COPY(&offset, (*proxy)->member);
-       debug_propro(1, "dtor", NULL, *proxy, &offset, NULL);
+       debug_propro(0, "free", NULL, *proxy, &offset, NULL);
 #endif
 
        if (*proxy) {
-               zval_ptr_dtor(&(*proxy)->container);
-
-               ZVAL_UNDEF(&(*proxy)->container);
+               if (!Z_ISUNDEF((*proxy)->container)) {
+                       zval_ptr_dtor(&(*proxy)->container);
+                       ZVAL_UNDEF(&(*proxy)->container);
+               }
                zend_string_release((*proxy)->member);
                (*proxy)->member = NULL;
                efree(*proxy);
@@ -218,8 +203,6 @@ void php_property_proxy_free(php_property_proxy_t **proxy)
        }
 
 #if DEBUG_PROPRO
-       debug_propro(-1, "dtor", NULL, NULL, &offset, NULL);
-
        zval_dtor(&offset);
 #endif
 }
@@ -270,6 +253,49 @@ static void destroy_obj(zend_object *object)
        zend_object_std_dtor(object);
 }
 
+static inline php_property_proxy_object_t *get_propro(zval *object)
+{
+       ZEND_ASSERT(Z_TYPE_P(object) == IS_OBJECT);
+       return PHP_PROPRO_PTR(Z_OBJ_P(object));
+}
+
+static HashTable *get_gc(zval *object, zval **table, int *n)
+{
+       php_property_proxy_object_t *o = get_propro(object);
+
+       if (Z_ISUNDEF(o->parent)) {
+               *table = &o->proxy->container;
+       } else {
+               *table = &o->parent;
+       }
+       *n = 1;
+       return NULL;
+}
+
+static HashTable *get_debug_info(zval *object, int *is_temp)
+{
+       HashTable *ht;
+       zval *zmember;
+       php_property_proxy_object_t *obj = get_propro(object);
+
+       ALLOC_HASHTABLE(ht);
+       zend_hash_init(ht, 3, NULL, NULL, 0);
+
+       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;
+}
+
 static ZEND_RESULT_CODE cast_obj(zval *object, zval *return_value, int type)
 {
        zval tmp;
@@ -301,12 +327,6 @@ static void set_obj(zval *object, zval *value) {
        set_proxied_value(object, value);
 }
 
-static inline php_property_proxy_object_t *get_propro(zval *object)
-{
-       ZEND_ASSERT(Z_TYPE_P(object) == IS_OBJECT);
-       return PHP_PROPRO_PTR(Z_OBJ_P(object));
-}
-
 static inline zval *get_container(zval *object, zval *tmp)
 {
        php_property_proxy_object_t *obj = get_propro(object);
@@ -317,7 +337,6 @@ static inline zval *get_container(zval *object, zval *tmp)
        } else {
                container = get_proxied_value(&obj->parent, tmp);
        }
-
        return container;
 }
 
@@ -326,11 +345,13 @@ static inline void set_container(zval *object, zval *container)
        php_property_proxy_object_t *obj = get_propro(object);
 
        if (Z_ISUNDEF(obj->parent)) {
-               zval tmp;
+               if (container != &obj->proxy->container) {
+                       zval tmp;
 
-               ZVAL_COPY_VALUE(&tmp, &obj->proxy->container);
-               ZVAL_COPY(&obj->proxy->container, container);
-               zval_ptr_dtor(&tmp);
+                       ZVAL_COPY_VALUE(&tmp, &obj->proxy->container);
+                       ZVAL_COPY(&obj->proxy->container, container);
+                       zval_ptr_dtor(&tmp);
+               }
        } else {
                set_proxied_value(&obj->parent, container);
        }
@@ -343,9 +364,9 @@ static inline zval *get_container_value(zval *container, zend_string *member, zv
        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:
@@ -360,61 +381,36 @@ static inline zval *get_container_value(zval *container, zend_string *member, zv
        return return_value;
 }
 
-static inline void cleanup_container(zval *container, zend_bool separated)
+static inline void cleanup_container(zval *object, zval *container, zend_bool separated)
 {
-#if DEBUG_PROPRO > 1
-       fprintf(stderr, ">> cleanup(%s) %p rc=%d\n",
-                       separated || (Z_REFCOUNTED_P(container) && !Z_REFCOUNT_P(container)) ? "yes" : "no",
-                       Z_REFCOUNTED_P(container) ? Z_COUNTED_P(container) : container,
-                       Z_REFCOUNTED_P(container) ? Z_REFCOUNT_P(container) : -1);
-#endif
        if (separated) {
                zval_ptr_dtor(container);
        }
 }
 
-static inline zend_bool separate_container(zval *container)
+static inline zend_bool separate_container(zval *object, zval *container)
 {
-#if DEBUG_PROPRO > 1
-       fprintf(stderr, ">> separate is_ref=%d rc=%d\n", Z_ISREF_P(container),
-                       Z_REFCOUNTED_P(container) ? Z_REFCOUNT_P(container) : -1);
-#endif
-
        switch (Z_TYPE_P(container)) {
        case IS_OBJECT:
-               break;
+               return 0;
 
        case IS_ARRAY:
-               if (Z_REFCOUNT_P(container) > 1) {
-                       SEPARATE_ZVAL(container);
-#if DEBUG_PROPRO > 1
-                       fprintf(stderr, ">> array_dup %p\n", Z_COUNTED_P(container));
-#endif
-                       return 1;
-               }
+               /* 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);
-#if DEBUG_PROPRO > 1
-               fprintf(stderr, ">> created %p\n", Z_COUNTED_P(container));
-#endif
-               return 1;
+               break;
 
        default:
                SEPARATE_ZVAL(container);
                Z_TRY_ADDREF_P(container);
                convert_to_array(container);
-#if DEBUG_PROPRO > 1
-               fprintf(stderr, ">> converted %p\n", Z_COUNTED_P(container));
-#endif
-               return 1;
+               break;
        }
 
-#if DEBUG_PROPRO > 1
-               fprintf(stderr, ">> nothing %p\n", Z_COUNTED_P(container));
-#endif
-       return 0;
+       return 1;
 }
 
 static inline zval *set_container_value(zval *container, zend_string *member, zval *value)
@@ -478,10 +474,10 @@ static void set_proxied_value(zval *object, zval *value)
 
                ZVAL_UNDEF(&tmp);
                container = get_container(object, &tmp);
-               separated = separate_container(container);
+               separated = separate_container(object, container);
                set_container_value(container, obj->proxy->member, value);
                set_container(object, container);
-               cleanup_container(container, separated);
+               cleanup_container(object, container, separated);
 
                Z_TRY_DELREF_P(value);
 
@@ -594,10 +590,10 @@ static void write_dimension(zval *object, zval *offset, zval *input_value)
 
        ZVAL_UNDEF(&tmp);
        array = get_proxied_value(object, &tmp);
-       separated = separate_container(array);
+       separated = separate_container(object, array);
        set_container_value(array, zs, input_value);
        set_proxied_value(object, array);
-       cleanup_container(array, separated);
+       cleanup_container(object, array, separated);
 
        if (zs) {
                zend_string_release(zs);
@@ -654,7 +650,6 @@ static PHP_METHOD(propro, __construct) {
                        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");
@@ -682,6 +677,8 @@ static PHP_MINIT_FUNCTION(propro)
                        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.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;