Commit 7cc143235d2 for php.net
commit 7cc143235d2be7b989348d37f465860835833a25
Author: Gina Peter Banyard <girgias@php.net>
Date: Wed Aug 5 16:23:31 2026 +0100
mbstring: deprecate passing objects as vars to mb_convert_variables()
RFC: https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_vars_parameter_of_mb_convert_variables
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index b475b83e02f..4059d8d35fd 100644
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@ -3820,7 +3820,7 @@ static bool mb_recursive_find_strings(zval *var, const unsigned char **val_list,
return false;
}
-static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_encoding, const mbfl_encoding* to_encoding)
+static bool mb_recursive_convert_variable(uint32_t arg_num, zval *var, const mbfl_encoding* from_encoding, const mbfl_encoding* to_encoding)
{
zval *entry, *orig_var;
@@ -3836,6 +3836,15 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
zval_ptr_dtor(orig_var);
ZVAL_STR(orig_var, ret);
} else if (Z_TYPE_P(var) == IS_ARRAY || Z_TYPE_P(var) == IS_OBJECT) {
+ if (Z_TYPE_P(var) == IS_OBJECT) {
+ php_error_docref(NULL, E_DEPRECATED,
+ "Passing an object for argument #%" PRIu32 " $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead",
+ arg_num
+ );
+ if (UNEXPECTED(EG(exception))) {
+ return true;
+ }
+ }
HashTable *ht = HASH_OF(var);
HashTable *orig_ht = ht;
@@ -3872,7 +3881,7 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
}
}
- if (mb_recursive_convert_variable(entry, from_encoding, to_encoding)) {
+ if (mb_recursive_convert_variable(arg_num, entry, from_encoding, to_encoding)) {
if (ht && ht != orig_ht) {
GC_TRY_UNPROTECT_RECURSION(ht);
}
@@ -3890,6 +3899,14 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
if (orig_ht) {
GC_TRY_UNPROTECT_RECURSION(orig_ht);
}
+ } else if (Z_TYPE_P(var) != IS_UNDEF) { /* Ignore unset properties */
+ php_error_docref(NULL, E_WARNING,
+ "Argument #%" PRIu32 " must be of type string|array|object or only contain entries of type string|array|object, %s given",
+ arg_num, zend_zval_type_name(var)
+ );
+ if (UNEXPECTED(EG(exception))) {
+ return true;
+ }
}
return false;
@@ -3985,7 +4002,7 @@ PHP_FUNCTION(mb_convert_variables)
for (size_t n = 0; n < argc; n++) {
zval *zv = &args[n];
ZVAL_DEREF(zv);
- if (mb_recursive_convert_variable(zv, from_encoding, to_encoding)) {
+ if (mb_recursive_convert_variable(n + 3, zv, from_encoding, to_encoding)) {
if (!EG(exception)) {
php_error_docref(NULL, E_WARNING, "Cannot handle recursive references");
}
diff --git a/ext/mbstring/tests/gh16261.phpt b/ext/mbstring/tests/gh16261.phpt
index 3573bd191c6..1fbbc5c208c 100644
--- a/ext/mbstring/tests/gh16261.phpt
+++ b/ext/mbstring/tests/gh16261.phpt
@@ -26,7 +26,8 @@ public function __construct(public string $x) {}
var_dump($test, $test2);
?>
---EXPECT--
+--EXPECTF--
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
object(Test)#1 (2) {
["x"]=>
string(5) "hello"
diff --git a/ext/mbstring/tests/mb_convert_variables.phpt b/ext/mbstring/tests/mb_convert_variables.phpt
index 2eb45946b5e..7558bded048 100644
--- a/ext/mbstring/tests/mb_convert_variables.phpt
+++ b/ext/mbstring/tests/mb_convert_variables.phpt
@@ -173,7 +173,7 @@ function __construct($value)
var_dump($bad_utf7imap);
?>
---EXPECT--
+--EXPECTF--
== SCALAR TEST ==
SJIS
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
@@ -191,21 +191,37 @@ function __construct($value)
EUC-JP
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
== OBJECT TEST ==
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
EUC-JP
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
EUC-JP
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
== SCALAR, ARRAY AND OBJECT TEST ==
+
+Deprecated: mb_convert_variables(): Passing an object for argument #7 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
EUC-JP
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3
== DEEPLY NESTED OBJECT/ARRAY TEST ==
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
UTF-8
42004c0041004800
== INVALID STRING ENCODING TEST ==
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
2500
# of illegal characters detected: 1
+
+Deprecated: mb_convert_variables(): Passing an object for argument #3 $vars to mb_convert_variables() is deprecated, call get_object_vars() first instead in %s on line %d
2600
# of illegal characters detected: 1
== ENCODING AUTO-DETECTION TEST ==
diff --git a/ext/mbstring/tests/mb_convert_variables_invalid_types.phpt b/ext/mbstring/tests/mb_convert_variables_invalid_types.phpt
new file mode 100644
index 00000000000..70972f04213
--- /dev/null
+++ b/ext/mbstring/tests/mb_convert_variables_invalid_types.phpt
@@ -0,0 +1,30 @@
+--TEST--
+mb_convert_variables(): $vars which are not string|array|object
+--EXTENSIONS--
+mbstring
+--FILE--
+<?php
+
+$i = 5;
+$a = [$i];
+
+try {
+ var_dump( mb_convert_variables('UTF-8', 'EUC-JP', $i, $a));
+} catch (\ValueError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+try {
+ var_dump( mb_convert_variables('UTF-8', 'EUC-JP', $a));
+} catch (\ValueError $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECTF--
+Warning: mb_convert_variables(): Argument #3 must be of type string|array|object or only contain entries of type string|array|object, int given in %s on line %d
+
+Warning: mb_convert_variables(): Argument #4 must be of type string|array|object or only contain entries of type string|array|object, int given in %s on line %d
+string(6) "EUC-JP"
+
+Warning: mb_convert_variables(): Argument #3 must be of type string|array|object or only contain entries of type string|array|object, int given in %s on line %d
+string(6) "EUC-JP"