diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2021-03-03 16:28:39 +0100 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2021-03-04 10:11:37 +0100 |
commit | 500b4b4945e3768afd2cfcae61548ef47e7f003f (patch) | |
tree | 5ccaa3fa9563789e054713a1a927945b5a6c9ea3 | |
parent | 4b59071844d4749e05a73d3d21527c7875e831f8 (diff) | |
download | php-git-500b4b4945e3768afd2cfcae61548ef47e7f003f.tar.gz |
Explicitly print reference wrappers in debug_zval_dump()
Closes GH-6750.
-rw-r--r-- | UPGRADING | 5 | ||||
-rw-r--r-- | ext/mysqli/tests/mysqli_result_references.phpt | 36 | ||||
-rw-r--r-- | ext/mysqli/tests/mysqli_result_references_mysqlnd.phpt | 34 | ||||
-rw-r--r-- | ext/standard/tests/general_functions/debug_zval_dump_o.phpt | 42 | ||||
-rw-r--r-- | ext/standard/tests/general_functions/debug_zval_dump_refs.phpt | 46 | ||||
-rw-r--r-- | ext/standard/var.c | 35 |
6 files changed, 142 insertions, 56 deletions
@@ -107,6 +107,11 @@ PHP 8.1 UPGRADE NOTES that ' is escaped to ' 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; } } |