summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2021-03-03 16:28:39 +0100
committerNikita Popov <nikita.ppv@gmail.com>2021-03-04 10:11:37 +0100
commit500b4b4945e3768afd2cfcae61548ef47e7f003f (patch)
tree5ccaa3fa9563789e054713a1a927945b5a6c9ea3
parent4b59071844d4749e05a73d3d21527c7875e831f8 (diff)
downloadphp-git-500b4b4945e3768afd2cfcae61548ef47e7f003f.tar.gz
Explicitly print reference wrappers in debug_zval_dump()
Closes GH-6750.
-rw-r--r--UPGRADING5
-rw-r--r--ext/mysqli/tests/mysqli_result_references.phpt36
-rw-r--r--ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt34
-rw-r--r--ext/standard/tests/general_functions/debug_zval_dump_o.phpt42
-rw-r--r--ext/standard/tests/general_functions/debug_zval_dump_refs.phpt46
-rw-r--r--ext/standard/var.c35
6 files changed, 142 insertions, 56 deletions
diff --git a/UPGRADING b/UPGRADING
index 495b831b79..cb331ea95b 100644
--- 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
diff --git a/ext/mysqli/tests/mysqli_result_references.phpt b/ext/mysqli/tests/mysqli_result_references.phpt
index c6b34896d8..be90b45794 100644
--- a/ext/mysqli/tests/mysqli_result_references.phpt
+++ b/ext/mysqli/tests/mysqli_result_references.phpt
@@ -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){
diff --git a/ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt b/ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt
index bdd37c79f3..5f5e352596 100644
--- a/ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt
+++ b/ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt
@@ -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"]=>
diff --git a/ext/standard/tests/general_functions/debug_zval_dump_o.phpt b/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
index e248bdc8be..89ed4a63d2 100644
--- a/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
+++ b/ext/standard/tests/general_functions/debug_zval_dump_o.phpt
@@ -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
index 0000000000..0af30d3379
--- /dev/null
+++ b/ext/standard/tests/general_functions/debug_zval_dump_refs.phpt
@@ -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)
+ }
+}
diff --git a/ext/standard/var.c b/ext/standard/var.c
index d4c99495d1..06b98b5b9d 100644
--- a/ext/standard/var.c
+++ b/ext/standard/var.c
@@ -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;
}
}