Commit 2581b6e7c2c for php
commit 2581b6e7c2cbdbe70fe934a910910409657e347b
Merge: 3fb2c088b77 1e24c518786
Author: Gina Peter Banyard <girgias@php.net>
Date: Sun Nov 8 07:44:21 2026 +0000
Merge branch 'PHP-8.5' into PHP-8.6
* PHP-8.5:
Zend: fix object_init_with_constructor() with positional args in named_params
zend_test: add additional tests with zend_object_init_with_constructor()
zend_test: add missing opcache enable INI setting
diff --cc Zend/zend_API.c
index 6ca5430d392,d196ff2061a..e43b3abf9ae
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@@ -1950,19 -1904,21 +1950,21 @@@ ZEND_API zend_result object_init_with_c
* However, if there are named arguments (and it is not empty),
* an Error must be thrown to be consistent with new ClassName() */
if (UNEXPECTED(named_params != NULL && zend_hash_num_elements(named_params) != 0)) {
- /* Throw standard Error */
- zend_string *arg_name = NULL;
- zend_hash_get_current_key(named_params, &arg_name, /* num_index */ NULL);
- ZEND_ASSERT(arg_name != NULL);
- zend_throw_error(NULL, "Unknown named parameter $%pS", arg_name);
- /* Do not call destructor, free object, and set arg to IS_UNDEF */
- zend_object_store_ctor_failed(obj);
- zval_ptr_dtor(arg);
- ZVAL_UNDEF(arg);
- return FAILURE;
- } else {
- return SUCCESS;
+ /* As named_arguments may contain positional args we need to check there is actually a string key */
+ ZEND_HASH_FOREACH_STR_KEY(named_params, zend_string *arg_name) {
+ if (arg_name == NULL) {
+ continue;
+ }
+ /* Throw standard Error */
- zend_throw_error(NULL, "Unknown named parameter $%s", ZSTR_VAL(arg_name));
++ zend_throw_error(NULL, "Unknown named parameter $%pS", arg_name);
+ /* Do not call destructor, free object, and set arg to IS_UNDEF */
+ zend_object_store_ctor_failed(obj);
+ zval_ptr_dtor(arg);
+ ZVAL_UNDEF(arg);
+ return FAILURE;
+ } ZEND_HASH_FOREACH_END();
}
+ return SUCCESS;
}
/* A constructor should not return a value, however if an exception is thrown
* zend_call_known_function() will set the retval to IS_UNDEF */
diff --cc ext/zend_test/test_arginfo.h
index c2509001e45,40c38d2e65c..2b81903ddeb
Binary files differ
diff --cc ext/zend_test/test_decl.h
index 291f7ab87af,00000000000..0dbb640bb1d
mode 100644,000000..100644
Binary files differ
diff --cc ext/zend_test/test_legacy_arginfo.h
index d6e1f758e20,00000000000..51f0a71d5b6
mode 100644,000000..100644
Binary files differ
diff --cc ext/zend_test/tests/zend_object_init_with_constructor_array.phpt
index 00000000000,0178114abcb..079eb76e2fb
mode 000000,100644..100644
--- a/ext/zend_test/tests/zend_object_init_with_constructor_array.phpt
+++ b/ext/zend_test/tests/zend_object_init_with_constructor_array.phpt
@@@ -1,0 -1,152 +1,150 @@@
+ --TEST--
+ Zend: Test object_init_with_constructor() API
+ --EXTENSIONS--
+ zend_test
+ --FILE--
+ <?php
+
+ class TestUserWithConstructorArgs {
+ public function __construct(int $int_param, string $string_param) {
- return new stdClass();
+ }
+ public function __destruct() {
+ echo 'Destructor for ', __CLASS__, PHP_EOL;
+ }
+ }
+
+ class TestUserWithConstructorNoParams {
+ public function __construct() {
- return new stdClass();
+ }
+ public function __destruct() {
+ echo 'Destructor for ', __CLASS__, PHP_EOL;
+ }
+ }
+
+ class TestUserWithoutConstructor {
+ public function __destruct() {
+ echo 'Destructor for ', __CLASS__, PHP_EOL;
+ }
+ }
+
+ $args = [5, 'str'];
+ $argsNamed = [5, 'string_param' => 'str'];
+ $argsNamedExtraUnknown = [5, 'string_param' => 'str', 'unknown' => 'unknown'];
+
+ echo "Testing param passing\n";
+ echo "Test TestUserWithConstructorArgs:\n";
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorArgs", $args);
+ var_dump($o);
+ unset($o);
+
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorArgs", $argsNamed);
+ var_dump($o);
+ unset($o);
+
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorArgs", $argsNamedExtraUnknown);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ echo "Test TestUserWithConstructorNoParams:\n";
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorNoParams", $args);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorNoParams", $argsNamed);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithConstructorNoParams", $argsNamedExtraUnknown);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ echo "Test TestUserWithoutConstructor:\n";
+ $o = zend_object_init_with_constructor_array("TestUserWithoutConstructor", $args);
+ var_dump($o);
+ unset($o);
+
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithoutConstructor", $argsNamed);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ $o = zend_object_init_with_constructor_array("TestUserWithoutConstructor", $argsNamedExtraUnknown);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ echo "Test _ZendTestMagicCall (internal class no ctor):\n";
+ try {
+ $o = zend_object_init_with_constructor_array("_ZendTestMagicCall", $args);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ $o = zend_object_init_with_constructor_array("_ZendTestMagicCall", $argsNamed);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ try {
+ $o = zend_object_init_with_constructor_array("_ZendTestMagicCall", $argsNamedExtraUnknown);
+ var_dump($o);
+ unset($o);
+ } catch (\Throwable $e) {
+ echo $e::class, ': ', $e->getMessage(), PHP_EOL;
+ }
+
+ ?>
+ --EXPECT--
+ Testing param passing
+ Test TestUserWithConstructorArgs:
+ object(TestUserWithConstructorArgs)#1 (0) {
+ }
+ Destructor for TestUserWithConstructorArgs
+ object(TestUserWithConstructorArgs)#1 (0) {
+ }
+ Destructor for TestUserWithConstructorArgs
+ Error: Unknown named parameter $unknown
+ Test TestUserWithConstructorNoParams:
+ object(TestUserWithConstructorNoParams)#1 (0) {
+ }
+ Destructor for TestUserWithConstructorNoParams
+ Error: Unknown named parameter $string_param
+ Error: Unknown named parameter $string_param
+ Test TestUserWithoutConstructor:
+ object(TestUserWithoutConstructor)#3 (0) {
+ }
+ Destructor for TestUserWithoutConstructor
+ Error: Unknown named parameter $string_param
+ Error: Unknown named parameter $string_param
+ Test _ZendTestMagicCall (internal class no ctor):
+ object(_ZendTestMagicCall)#2 (0) {
+ }
+ Error: Unknown named parameter $string_param
+ Error: Unknown named parameter $string_param