Commit f8c854e82fa for php.net

commit f8c854e82faec850981a4a65e6c64a822ec580af
Author: Gina Peter Banyard <girgias@php.net>
Date:   Wed Aug 5 15:48:24 2026 +0100

    zlib: deprecate passing objects as array

    Implements RFCs:
    - https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_for_options_parameter_of_deflate_init_and_inflate_init
    - https://wiki.php.net/rfc/deprecations_php_8_6#passing_objects_as_parameters_to_the_zlibinflate_and_zlibdeflate_stream_filters

diff --git a/ext/zlib/tests/filter_broken_object_options.phpt b/ext/zlib/tests/filter_broken_object_options.phpt
index beb0fef9fb1..a43c85f3671 100644
--- a/ext/zlib/tests/filter_broken_object_options.phpt
+++ b/ext/zlib/tests/filter_broken_object_options.phpt
@@ -17,5 +17,8 @@ class Params {
 fwrite($fp, "Hello world, hopefully not broken\n");

 ?>
---EXPECT--
+--EXPECTF--
+Deprecated: stream_filter_append(): Passing an object for filter parameters for zlib.deflate is deprecated, call get_object_vars() first instead in %s on line %d
+
+Deprecated: stream_filter_append(): Passing an object for filter parameters for zlib.inflate is deprecated, call get_object_vars() first instead in %s on line %d
 Hello world, hopefully not broken
diff --git a/ext/zlib/tests/gh17745.phpt b/ext/zlib/tests/gh17745.phpt
index 64331269dcd..5e522ee9614 100644
--- a/ext/zlib/tests/gh17745.phpt
+++ b/ext/zlib/tests/gh17745.phpt
@@ -13,8 +13,11 @@ class Options {
 }
 var_dump(deflate_init(ZLIB_ENCODING_RAW, new Options));
 ?>
---EXPECT--
+--EXPECTF--
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
 object(DeflateContext)#2 (0) {
 }
+
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
 object(DeflateContext)#3 (0) {
 }
diff --git a/ext/zlib/tests/gh17745_inflate.phpt b/ext/zlib/tests/gh17745_inflate.phpt
new file mode 100644
index 00000000000..c87f0fbea9d
--- /dev/null
+++ b/ext/zlib/tests/gh17745_inflate.phpt
@@ -0,0 +1,23 @@
+--TEST--
+GH-17745 (zlib extension incorrectly handles object arguments)
+--EXTENSIONS--
+zlib
+--FILE--
+<?php
+$obj = new stdClass;
+$obj->level = 3;
+var_dump(inflate_init(ZLIB_ENCODING_RAW, $obj));
+
+class Options {
+    public int $level = 3;
+}
+var_dump(inflate_init(ZLIB_ENCODING_RAW, new Options));
+?>
+--EXPECTF--
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+object(InflateContext)#2 (0) {
+}
+
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+object(InflateContext)#3 (0) {
+}
diff --git a/ext/zlib/tests/gh22142.phpt b/ext/zlib/tests/gh22142.phpt
index 9bbb9332df3..481ffef342a 100644
--- a/ext/zlib/tests/gh22142.phpt
+++ b/ext/zlib/tests/gh22142.phpt
@@ -16,5 +16,6 @@ class Options {
 }

 ?>
---EXPECT--
+--EXPECTF--
+Deprecated: deflate_init(): Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
 TypeError: deflate_init(): Argument #2 ($options) the value for option "level" must be of type int, null given
diff --git a/ext/zlib/tests/gh22142_inflate.phpt b/ext/zlib/tests/gh22142_inflate.phpt
new file mode 100644
index 00000000000..853099e4911
--- /dev/null
+++ b/ext/zlib/tests/gh22142_inflate.phpt
@@ -0,0 +1,21 @@
+--TEST--
+GH-22142 (Assertion failure in zendi_try_get_long() on IS_UNDEF)
+--EXTENSIONS--
+zlib
+--FILE--
+<?php
+
+class Options {
+    public int $window;
+}
+
+try {
+    inflate_init(ZLIB_ENCODING_DEFLATE, new Options());
+} catch (TypeError $e) {
+    echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+}
+
+?>
+--EXPECTF--
+Deprecated: inflate_init(): Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead in %s on line %d
+TypeError: inflate_init(): Argument #2 ($options) the value for option "window" must be of type int, null given
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 5b630d74c88..44ab23233ac 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -881,12 +881,24 @@ PHP_FUNCTION(inflate_init)
 	zend_long encoding, window = 15;
 	char *dict = NULL;
 	size_t dictlen = 0;
+	zval *options_zv = NULL;
 	HashTable *options = (HashTable *) &zend_empty_array;

-	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
+	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|A", &encoding, &options_zv)) {
 		RETURN_THROWS();
 	}

+	if (options_zv) {
+		if (Z_TYPE_P(options_zv) == IS_OBJECT) {
+			php_error_docref(NULL, E_DEPRECATED,
+				"Passing an object for argument #2 $option to inflate_init() is deprecated, call get_object_vars() first instead");
+			if (UNEXPECTED(EG(exception))) {
+				RETURN_THROWS();
+			}
+		}
+		options = HASH_OF(options_zv);
+	}
+
 	if (!zlib_get_long_option(options, ZEND_STRL("window"), &window)) {
 		RETURN_THROWS();
 	}
@@ -1100,12 +1112,24 @@ PHP_FUNCTION(deflate_init)
 	zend_long encoding, level = -1, memory = 8, window = 15, strategy = Z_DEFAULT_STRATEGY;
 	char *dict = NULL;
 	size_t dictlen = 0;
+	zval *options_zv = NULL;
 	HashTable *options = (HashTable*)&zend_empty_array;

-	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|H", &encoding, &options)) {
+	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l|A", &encoding, &options_zv)) {
 		RETURN_THROWS();
 	}

+	if (options_zv) {
+		if (Z_TYPE_P(options_zv) == IS_OBJECT) {
+			php_error_docref(NULL, E_DEPRECATED,
+				"Passing an object for argument #2 $option to deflate_init() is deprecated, call get_object_vars() first instead");
+			if (UNEXPECTED(EG(exception))) {
+				RETURN_THROWS();
+			}
+		}
+		options = HASH_OF(options_zv);
+	}
+
 	if (!zlib_get_long_option(options, ZEND_STRL("level"), &level)) {
 		RETURN_THROWS();
 	}
diff --git a/ext/zlib/zlib_filter.c b/ext/zlib/zlib_filter.c
index 2d0e4fbb7fa..4e6c1a54c0f 100644
--- a/ext/zlib/zlib_filter.c
+++ b/ext/zlib/zlib_filter.c
@@ -361,6 +361,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 	php_zlib_filter_data *data;
 	int status;

+	if (filterparams && Z_TYPE_P(filterparams) == IS_OBJECT) {
+		php_error_docref("filters.compression", E_DEPRECATED,
+			"Passing an object for filter parameters for %s is deprecated, call get_object_vars() first instead", filtername);
+		if (UNEXPECTED(EG(exception))) {
+			return NULL;
+		}
+	}
+
 	if (php_stream_filter_parse_write_seek_mode(filterparams, &write_seekable) == FAILURE) {
 		return NULL;
 	}
@@ -368,7 +376,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 	/* Create this filter */
 	data = pecalloc(1, sizeof(php_zlib_filter_data), persistent);
 	if (!data) {
-		php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
+		php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", sizeof(php_zlib_filter_data));
 		return NULL;
 	}

@@ -380,14 +388,14 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 	data->strm.avail_out = data->outbuf_len = data->inbuf_len = 0x8000;
 	data->strm.next_in = data->inbuf = (Bytef *) pemalloc(data->inbuf_len, persistent);
 	if (!data->inbuf) {
-		php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
+		php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", data->inbuf_len);
 		pefree(data, persistent);
 		return NULL;
 	}
 	data->strm.avail_in = 0;
 	data->strm.next_out = data->outbuf = (Bytef *) pemalloc(data->outbuf_len, persistent);
 	if (!data->outbuf) {
-		php_error_docref(NULL, E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
+		php_error_docref("filters.compression", E_WARNING, "Failed allocating %zd bytes", data->outbuf_len);
 		pefree(data->inbuf, persistent);
 		pefree(data, persistent);
 		return NULL;
@@ -407,7 +415,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 				/* log-2 base of history window (9 - 15) */
 				zend_long tmp = zval_get_long(tmpzval);
 				if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 32) {
-					php_error_docref(NULL, E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
+					php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
 				} else {
 					windowBits = tmp;
 				}
@@ -444,7 +452,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 						/* Memory Level (1 - 9) */
 						tmp = zval_get_long(tmpzval);
 						if (tmp < 1 || tmp > MAX_MEM_LEVEL) {
-							php_error_docref(NULL, E_WARNING, "Invalid parameter given for memory level (" ZEND_LONG_FMT ")", tmp);
+							php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for memory level (" ZEND_LONG_FMT ")", tmp);
 						} else {
 							memLevel = tmp;
 						}
@@ -454,7 +462,7 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 						/* log-2 base of history window (9 - 15) */
 						tmp = zval_get_long(tmpzval);
 						if (tmp < -MAX_WBITS || tmp > MAX_WBITS + 16) {
-							php_error_docref(NULL, E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
+							php_error_docref("filters.compression", E_WARNING, "Invalid parameter given for window size (" ZEND_LONG_FMT ")", tmp);
 						} else {
 							windowBits = tmp;
 						}
@@ -475,13 +483,13 @@ static php_stream_filter *php_zlib_filter_create(const char *filtername, zval *f
 factory_setlevel:
 					/* Set compression level within reason (-1 == default, 0 == none, 1-9 == least to most compression */
 					if (tmp < -1 || tmp > 9) {
-						php_error_docref(NULL, E_WARNING, "Invalid compression level specified. (" ZEND_LONG_FMT ")", tmp);
+						php_error_docref("filters.compression", E_WARNING, "Invalid compression level specified. (" ZEND_LONG_FMT ")", tmp);
 					} else {
 						level = tmp;
 					}
 					break;
 				default:
-					php_error_docref(NULL, E_WARNING, "Invalid filter parameter, ignored");
+					php_error_docref("filters.compression", E_WARNING, "Invalid filter parameter, ignored");
 			}
 		}