]> granicus.if.org Git - php/commitdiff
Explicitly print reference wrappers in debug_zval_dump()
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 3 Mar 2021 15:28:39 +0000 (16:28 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 4 Mar 2021 09:11:37 +0000 (10:11 +0100)
Closes GH-6750.

UPGRADING
ext/mysqli/tests/mysqli_result_references.phpt
ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt
ext/standard/tests/general_functions/debug_zval_dump_o.phpt
ext/standard/tests/general_functions/debug_zval_dump_refs.phpt [new file with mode: 0644]
ext/standard/var.c

index 495b831b7955a37a7268c10647f620681e3c1a91..cb331ea95b4a5677af7918fc12b73e88fc41b91d 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -107,6 +107,11 @@ PHP 8.1 UPGRADE NOTES
     that ' is escaped to &#039; while previously it was left alone.
     Additionally, malformed UTF-8 will be replaced by a Unicode substitution
     character, instead of resulting in an empty string.
+  . debug_zval_dump() will now print reference wrappers with their refcount,
+    instead of only prepending a "&" to the value. This more accurately models
+    reference representation since PHP 7.0.
+  . debug_zval_dump() will not print "interned" instead of a dummy refcount of
+    one for interned strings and immutable arrays.
 
 ========================================
 2. New Features
index c6b34896d8410ea7ff8da73d2376899e50e34d44..be90b45794d83ebba45e2ae3b6f847929796108d 100644 (file)
@@ -87,51 +87,69 @@ array(7) refcount(2){
   [0]=>
   array(2) refcount(1){
     ["id"]=>
-    int(1)
+    reference refcount(1) {
+      int(1)
+    }
     ["label"]=>
     string(1) "a" refcount(%d)
   }
   [1]=>
   array(2) refcount(1){
     ["id"]=>
-    int(2)
+    reference refcount(1) {
+      int(2)
+    }
     ["label"]=>
     string(1) "b" refcount(%d)
   }
   [2]=>
   array(2) refcount(1){
     ["id"]=>
-    int(1)
+    reference refcount(1) {
+      int(1)
+    }
     ["label"]=>
     string(1) "a" refcount(%d)
   }
   [3]=>
   array(2) refcount(1){
     ["id"]=>
-    int(2)
+    reference refcount(1) {
+      int(2)
+    }
     ["label"]=>
     string(1) "b" refcount(%d)
   }
   [4]=>
   array(3) refcount(1){
     ["id"]=>
-    &int(3)
+    reference refcount(2) {
+      int(3)
+    }
     ["label"]=>
     string(1) "a" refcount(%d)
     ["id2"]=>
-    &int(3)
+    reference refcount(2) {
+      int(3)
+    }
   }
   [5]=>
   array(3) refcount(1){
     ["id"]=>
-    &int(4)
+    reference refcount(2) {
+      int(4)
+    }
     ["label"]=>
     string(1) "b" refcount(%d)
     ["id2"]=>
-    &int(4)
+    reference refcount(2) {
+      int(4)
+    }
   }
   [6]=>
-  &object(mysqli_result)#%d (0) refcount(%d){
+  reference refcount(2) {
+    object(mysqli_result)#2 (0) refcount(1){
+    }
   }
 }
 array(1) refcount(2){
index bdd37c79f3cf915256e72bccbf788c69c8737d4c..5f5e35259644988221c57a216beb68bcbd6ca17d 100644 (file)
@@ -55,7 +55,9 @@ array(1) refcount(%d){
   [0]=>
   array(4) refcount(%d){
     ["row_ref"]=>
-    &NULL
+    reference refcount(2) {
+      NULL
+    }
     ["row_copy"]=>
     array(2) refcount(1){
       ["id"]=>
@@ -64,7 +66,9 @@ array(1) refcount(%d){
       string(1) "a" interned
     }
     ["id_ref"]=>
-    string(1) "1" interned
+    reference refcount(1) {
+      string(1) "1" interned
+    }
     ["id_copy"]=>
     string(1) "1" interned
   }
@@ -73,7 +77,9 @@ array(2) refcount(%d){
   [0]=>
   array(4) refcount(%d){
     ["row_ref"]=>
-    &NULL
+    reference refcount(2) {
+      NULL
+    }
     ["row_copy"]=>
     array(2) refcount(%d){
       ["id"]=>
@@ -82,18 +88,24 @@ array(2) refcount(%d){
       string(1) "a" interned
     }
     ["id_ref"]=>
-    string(1) "1" interned
+    reference refcount(1) {
+      string(1) "1" interned
+    }
     ["id_copy"]=>
     string(1) "1" interned
   }
   [1]=>
   array(5) refcount(%d){
     ["row_ref"]=>
-    &array(2) refcount(%d){
-      ["id"]=>
-      &string(1) "2" interned
-      ["label"]=>
-      string(1) "b" interned
+    reference refcount(2) {
+      array(2) refcount(1){
+        ["id"]=>
+        reference refcount(2) {
+          string(1) "2" interned
+        }
+        ["label"]=>
+        string(1) "b" interned
+      }
     }
     ["row_copy"]=>
     array(2) refcount(%d){
@@ -103,7 +115,9 @@ array(2) refcount(%d){
       string(1) "b" interned
     }
     ["id_ref"]=>
-    &string(1) "2" interned
+    reference refcount(2) {
+      string(1) "2" interned
+    }
     ["id_copy"]=>
     string(1) "2" interned
     ["id_copy_mod"]=>
index e248bdc8be1844de51f8881063887974930e5121..89ed4a63d21a8e1183abd50f20538889d7a5d26a 100644 (file)
@@ -345,26 +345,30 @@ object(object_class)#%d (7) refcount(%d){
   ["object_class1"]=>
   *RECURSION*
   ["obj"]=>
-  &object(object_class)#%d (7) refcount(%d){
-    ["value1"]=>
-    int(5)
-    ["value2":"object_class":private]=>
-    int(10)
-    ["value3":protected]=>
-    int(20)
-    ["value4"]=>
-    int(30)
-    ["array_var"]=>
-    array(2) refcount(%d){
-      ["key1"]=>
-      int(1)
-      ["key2 "]=>
-      int(3)
+  reference refcount(2) {
+    object(object_class)#8 (7) refcount(2){
+      ["value1"]=>
+      int(5)
+      ["value2":"object_class":private]=>
+      int(10)
+      ["value3":protected]=>
+      int(20)
+      ["value4"]=>
+      int(30)
+      ["array_var"]=>
+      array(2) refcount(7){
+        ["key1"]=>
+        int(1)
+        ["key2 "]=>
+        int(3)
+      }
+      ["object_class1"]=>
+      *RECURSION*
+      ["obj"]=>
+      reference refcount(2) {
+        *RECURSION*
+      }
     }
-    ["object_class1"]=>
-    *RECURSION*
-    ["obj"]=>
-    *RECURSION*
   }
 }
 Done
diff --git a/ext/standard/tests/general_functions/debug_zval_dump_refs.phpt b/ext/standard/tests/general_functions/debug_zval_dump_refs.phpt
new file mode 100644 (file)
index 0000000..0af30d3
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+References in debug_zval_dump()
+--FILE--
+<?php
+
+$r = 1;
+$a = [&$r];
+debug_zval_dump($a);
+$a[] =& $r;
+debug_zval_dump($a);
+unset($a[1]);
+debug_zval_dump($a);
+unset($r);
+// rc=1 singleton ref remains
+debug_zval_dump($a);
+
+?>
+--EXPECT--
+array(1) refcount(2){
+  [0]=>
+  reference refcount(2) {
+    int(1)
+  }
+}
+array(2) refcount(2){
+  [0]=>
+  reference refcount(3) {
+    int(1)
+  }
+  [1]=>
+  reference refcount(3) {
+    int(1)
+  }
+}
+array(1) refcount(2){
+  [0]=>
+  reference refcount(2) {
+    int(1)
+  }
+}
+array(1) refcount(2){
+  [0]=>
+  reference refcount(1) {
+    int(1)
+  }
+}
index d4c99495d1acad36780ab52533ed4bc28ea34b3f..06b98b5b9d3770bb4bc0d471f30d405b005a6d73 100644 (file)
@@ -269,7 +269,6 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
 {
        HashTable *myht = NULL;
        zend_string *class_name;
-       int is_ref = 0;
        zend_ulong index;
        zend_string *key;
        zval *val;
@@ -279,25 +278,24 @@ PHPAPI void php_debug_zval_dump(zval *struc, int level) /* {{{ */
                php_printf("%*c", level - 1, ' ');
        }
 
-again:
        switch (Z_TYPE_P(struc)) {
        case IS_FALSE:
-               php_printf("%sbool(false)\n", COMMON);
+               PUTS("bool(false)\n");
                break;
        case IS_TRUE:
-               php_printf("%sbool(true)\n", COMMON);
+               PUTS("bool(true)\n");
                break;
        case IS_NULL:
-               php_printf("%sNULL\n", COMMON);
+               PUTS("NULL\n");
                break;
        case IS_LONG:
-               php_printf("%sint(" ZEND_LONG_FMT ")\n", COMMON, Z_LVAL_P(struc));
+               php_printf("int(" ZEND_LONG_FMT ")\n", Z_LVAL_P(struc));
                break;
        case IS_DOUBLE:
-               php_printf_unchecked("%sfloat(%.*H)\n", COMMON, (int) PG(serialize_precision), Z_DVAL_P(struc));
+               php_printf_unchecked("float(%.*H)\n", (int) PG(serialize_precision), Z_DVAL_P(struc));
                break;
        case IS_STRING:
-               php_printf("%sstring(%zd) \"", COMMON, Z_STRLEN_P(struc));
+               php_printf("string(%zd) \"", Z_STRLEN_P(struc));
                PHPWRITE(Z_STRVAL_P(struc), Z_STRLEN_P(struc));
                if (Z_REFCOUNTED_P(struc)) {
                        php_printf("\" refcount(%u)\n", Z_REFCOUNT_P(struc));
@@ -318,9 +316,9 @@ again:
                count = zend_hash_num_elements(myht);
                if (Z_REFCOUNTED_P(struc)) {
                        /* -1 because of ADDREF above. */
-                       php_printf("%sarray(%d) refcount(%u){\n", COMMON, count, Z_REFCOUNT_P(struc) - 1);
+                       php_printf("array(%d) refcount(%u){\n", count, Z_REFCOUNT_P(struc) - 1);
                } else {
-                       php_printf("%sarray(%d) interned {\n", COMMON, count);
+                       php_printf("array(%d) interned {\n", count);
                }
                ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) {
                        zval_array_element_dump(val, index, key, level);
@@ -345,7 +343,7 @@ again:
                        GC_PROTECT_RECURSION(myht);
                }
                class_name = Z_OBJ_HANDLER_P(struc, get_class_name)(Z_OBJ_P(struc));
-               php_printf("%sobject(%s)#%d (%d) refcount(%u){\n", COMMON, ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
+               php_printf("object(%s)#%d (%d) refcount(%u){\n", ZSTR_VAL(class_name), Z_OBJ_HANDLE_P(struc), myht ? zend_array_count(myht) : 0, Z_REFCOUNT_P(struc));
                zend_string_release_ex(class_name, 0);
                if (myht) {
                        ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, val) {
@@ -372,18 +370,19 @@ again:
                break;
        case IS_RESOURCE: {
                const char *type_name = zend_rsrc_list_get_rsrc_type(Z_RES_P(struc));
-               php_printf("%sresource(%d) of type (%s) refcount(%u)\n", COMMON, Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
+               php_printf("resource(%d) of type (%s) refcount(%u)\n", Z_RES_P(struc)->handle, type_name ? type_name : "Unknown", Z_REFCOUNT_P(struc));
                break;
        }
        case IS_REFERENCE:
-               //??? hide references with refcount==1 (for compatibility)
-               if (Z_REFCOUNT_P(struc) > 1) {
-                       is_ref = 1;
+               php_printf("reference refcount(%u) {\n", Z_REFCOUNT_P(struc));
+               php_debug_zval_dump(Z_REFVAL_P(struc), level + 2);
+               if (level > 1) {
+                       php_printf("%*c", level - 1, ' ');
                }
-               struc = Z_REFVAL_P(struc);
-               goto again;
+               PUTS("}\n");
+               break;
        default:
-               php_printf("%sUNKNOWN:0\n", COMMON);
+               PUTS("UNKNOWN:0\n");
                break;
        }
 }