mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Let closure created from magic method accept named parameters
Implements GH-11348. Closes GH-11364.
This commit is contained in:
parent
16a63d7b07
commit
61e1f8aaeb
4 changed files with 128 additions and 2 deletions
2
NEWS
2
NEWS
|
@ -40,6 +40,8 @@ PHP NEWS
|
|||
. Fix bug #79836 (Segfault in concat_function). (nielsdos)
|
||||
. Fix bug #81705 (type confusion/UAF on set_error_handler with concat
|
||||
operation). (nielsdos)
|
||||
. Fix GH-11348 (Closure created from magic method does not accept named
|
||||
arguments). (nielsdos)
|
||||
|
||||
- Date:
|
||||
. Implement More Appropriate Date/Time Exceptions RFC. (Derick)
|
||||
|
|
|
@ -58,6 +58,7 @@ PHP 8.3 UPGRADE NOTES
|
|||
RFC: https://wiki.php.net/rfc/readonly_amendments
|
||||
. Class, interface, trait, and enum constants now support type
|
||||
declarations. RFC: https://wiki.php.net/rfc/typed_class_constants
|
||||
. Closures created from magic methods can now accept named arguments.
|
||||
|
||||
- Posix
|
||||
. posix_getrlimit() now takes an optional $res parameter to allow fetching a
|
||||
|
|
112
Zend/tests/trampoline_closure_named_arguments.phpt
Normal file
112
Zend/tests/trampoline_closure_named_arguments.phpt
Normal file
|
@ -0,0 +1,112 @@
|
|||
--TEST--
|
||||
Trampoline closure created from magic method accepts named arguments
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
public function __call($name, $args) {
|
||||
var_dump($name, $args);
|
||||
}
|
||||
public static function __callStatic($name, $args) {
|
||||
var_dump($name, $args);
|
||||
}
|
||||
}
|
||||
|
||||
$test = new Test;
|
||||
|
||||
echo "-- Non-static cases --\n";
|
||||
$test->test(1, 2, a: 123);
|
||||
$test->test(...)(1, 2);
|
||||
$test->test(...)(1, 2, a: 123, b: $test);
|
||||
$test->test(...)(a: 123, b: $test);
|
||||
$test->test(...)();
|
||||
|
||||
echo "-- Static cases --\n";
|
||||
Test::testStatic(1, 2, a: 123);
|
||||
Test::testStatic(...)(1, 2);
|
||||
Test::testStatic(...)(1, 2, a: 123, b: $test);
|
||||
Test::testStatic(...)(a: 123, b: $test);
|
||||
Test::testStatic(...)();
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
-- Non-static cases --
|
||||
string(4) "test"
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
["a"]=>
|
||||
int(123)
|
||||
}
|
||||
string(4) "test"
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
}
|
||||
string(4) "test"
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
["a"]=>
|
||||
int(123)
|
||||
["b"]=>
|
||||
object(Test)#1 (0) {
|
||||
}
|
||||
}
|
||||
string(4) "test"
|
||||
array(2) {
|
||||
["a"]=>
|
||||
int(123)
|
||||
["b"]=>
|
||||
object(Test)#1 (0) {
|
||||
}
|
||||
}
|
||||
string(4) "test"
|
||||
array(0) {
|
||||
}
|
||||
-- Static cases --
|
||||
string(10) "testStatic"
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
["a"]=>
|
||||
int(123)
|
||||
}
|
||||
string(10) "testStatic"
|
||||
array(2) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
}
|
||||
string(10) "testStatic"
|
||||
array(4) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
["a"]=>
|
||||
int(123)
|
||||
["b"]=>
|
||||
object(Test)#1 (0) {
|
||||
}
|
||||
}
|
||||
string(10) "testStatic"
|
||||
array(2) {
|
||||
["a"]=>
|
||||
int(123)
|
||||
["b"]=>
|
||||
object(Test)#1 (0) {
|
||||
}
|
||||
}
|
||||
string(10) "testStatic"
|
||||
array(0) {
|
||||
}
|
|
@ -294,7 +294,18 @@ static ZEND_NAMED_FUNCTION(zend_closure_call_magic) /* {{{ */ {
|
|||
fci.params = params;
|
||||
fci.param_count = 2;
|
||||
ZVAL_STR(&fci.params[0], EX(func)->common.function_name);
|
||||
if (ZEND_NUM_ARGS()) {
|
||||
if (EX_CALL_INFO() & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
|
||||
zend_string *name;
|
||||
zval *named_param_zval;
|
||||
array_init_size(&fci.params[1], ZEND_NUM_ARGS() + zend_hash_num_elements(EX(extra_named_params)));
|
||||
/* Avoid conversion from packed to mixed later. */
|
||||
zend_hash_real_init_mixed(Z_ARRVAL(fci.params[1]));
|
||||
zend_copy_parameters_array(ZEND_NUM_ARGS(), &fci.params[1]);
|
||||
ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EX(extra_named_params), name, named_param_zval) {
|
||||
Z_TRY_ADDREF_P(named_param_zval);
|
||||
zend_hash_add_new(Z_ARRVAL(fci.params[1]), name, named_param_zval);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
} else if (ZEND_NUM_ARGS()) {
|
||||
array_init_size(&fci.params[1], ZEND_NUM_ARGS());
|
||||
zend_copy_parameters_array(ZEND_NUM_ARGS(), &fci.params[1]);
|
||||
} else {
|
||||
|
@ -841,7 +852,7 @@ void zend_closure_from_frame(zval *return_value, zend_execute_data *call) { /* {
|
|||
|
||||
memset(&trampoline, 0, sizeof(zend_internal_function));
|
||||
trampoline.type = ZEND_INTERNAL_FUNCTION;
|
||||
trampoline.fn_flags = mptr->common.fn_flags & ZEND_ACC_STATIC;
|
||||
trampoline.fn_flags = mptr->common.fn_flags & (ZEND_ACC_STATIC | ZEND_ACC_VARIADIC);
|
||||
trampoline.handler = zend_closure_call_magic;
|
||||
trampoline.function_name = mptr->common.function_name;
|
||||
trampoline.scope = mptr->common.scope;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue