Skip to content

Commit 0003399

Browse files
committed
Support call_user_func with named params
Drop the fci_named distinction. It turned out to be too cumbersome to support. It's better to update affected fci initializations.
1 parent d2470f3 commit 0003399

File tree

9 files changed

+63
-50
lines changed

9 files changed

+63
-50
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
call_user_func() with named parameters
3+
--FILE--
4+
<?php
5+
6+
function test($a = 'a', $b = 'b') {
7+
var_dump($a, $b);
8+
}
9+
10+
call_user_func('test', 'A', b: 'B');
11+
call_user_func('test', b: 'B', a: 'A');
12+
call_user_func('test', b: 'B');
13+
14+
?>
15+
--EXPECT--
16+
string(1) "A"
17+
string(1) "B"
18+
string(1) "A"
19+
string(1) "B"
20+
string(1) "a"
21+
string(1) "B"

Zend/tests/named_params/internal_variadics.phpt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,7 @@ try {
1515
echo $e->getMessage(), "\n";
1616
}
1717

18-
// TODO: Should this work?
19-
try {
20-
call_user_func('strlen', str: 'foo');
21-
} catch (ArgumentCountError $e) {
22-
echo $e->getMessage(), "\n";
23-
}
24-
2518
?>
2619
--EXPECT--
2720
array_merge() does not accept unknown named parameters
2821
array_diff_key() does not accept unknown named parameters
29-
call_user_func() does not accept unknown named parameters

Zend/zend_API.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3357,6 +3357,7 @@ ZEND_API int zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fca
33573357
fci->retval = NULL;
33583358
fci->param_count = 0;
33593359
fci->params = NULL;
3360+
fci->named_params = NULL;
33603361
fci->no_separation = 1;
33613362

33623363
return SUCCESS;

Zend/zend_API.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,8 @@ typedef struct _zend_fcall_info {
4848
zend_object *object;
4949
zend_bool no_separation;
5050
uint32_t param_count;
51-
} zend_fcall_info;
52-
53-
typedef struct _zend_fcall_info_named {
54-
zend_fcall_info fci;
5551
HashTable *named_params;
56-
} zend_fcall_info_named;
52+
} zend_fcall_info;
5753

5854
typedef struct _zend_fcall_info_cache {
5955
zend_function *function_handler;

Zend/zend_closures.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ ZEND_METHOD(Closure, call)
168168
fci.size = sizeof(fci);
169169
ZVAL_OBJ(&fci.function_name, &closure->std);
170170
fci.retval = &closure_result;
171+
fci.named_params = NULL;
171172
fci.no_separation = 1;
172173

173174
if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(closure_result) != IS_UNDEF) {

Zend/zend_exceptions.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ ZEND_METHOD(Exception, __toString)
672672
fci.retval = &trace;
673673
fci.param_count = 0;
674674
fci.params = NULL;
675+
fci.named_params = NULL;
675676
fci.no_separation = 1;
676677

677678
zend_call_function(&fci, NULL);

Zend/zend_execute_API.c

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ int _call_user_function_ex(zval *object, zval *function_name, zval *retval_ptr,
629629
fci.retval = retval_ptr;
630630
fci.param_count = param_count;
631631
fci.params = params;
632+
fci.named_params = NULL;
632633
fci.no_separation = (zend_bool) no_separation;
633634

634635
return zend_call_function(&fci, NULL);
@@ -655,8 +656,7 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
655656
return FAILURE; /* we would result in an instable executor otherwise */
656657
}
657658

658-
ZEND_ASSERT(fci->size == sizeof(zend_fcall_info)
659-
|| fci->size == sizeof(zend_fcall_info_named));
659+
ZEND_ASSERT(fci->size == sizeof(zend_fcall_info));
660660

661661
/* Initialize execute_data */
662662
if (!EG(current_execute_data)) {
@@ -768,32 +768,29 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
768768
ZVAL_COPY(param, arg);
769769
}
770770

771-
if (fci->size == sizeof(zend_fcall_info_named)) {
772-
HashTable *named_params = ((zend_fcall_info_named *) fci)->named_params;
773-
if (named_params) {
774-
zend_string *name;
775-
zval *val;
776-
ZEND_HASH_FOREACH_STR_KEY_VAL(named_params, name, val) {
777-
ZEND_ASSERT(name && "named_params may only contain named params");
778-
779-
void *cache_slot = NULL;
780-
uint32_t arg_num;
781-
zval *target = zend_handle_named_arg(&call, name, &arg_num, &cache_slot);
782-
if (!target) {
783-
zend_vm_stack_free_args(call);
784-
zend_vm_stack_free_call_frame(call);
785-
if (EG(current_execute_data) == &dummy_execute_data) {
786-
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
787-
}
788-
return FAILURE;
771+
if (fci->named_params) {
772+
zend_string *name;
773+
zval *val;
774+
ZEND_HASH_FOREACH_STR_KEY_VAL(fci->named_params, name, val) {
775+
ZEND_ASSERT(name && "named_params may only contain named params");
776+
777+
void *cache_slot = NULL;
778+
uint32_t arg_num;
779+
zval *target = zend_handle_named_arg(&call, name, &arg_num, &cache_slot);
780+
if (!target) {
781+
zend_vm_stack_free_args(call);
782+
zend_vm_stack_free_call_frame(call);
783+
if (EG(current_execute_data) == &dummy_execute_data) {
784+
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
789785
}
786+
return FAILURE;
787+
}
790788

791-
/* TODO */
792-
/*if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) {
793-
}*/
794-
ZVAL_COPY(target, val);
795-
} ZEND_HASH_FOREACH_END();
796-
}
789+
/* TODO */
790+
/*if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) {
791+
}*/
792+
ZVAL_COPY(target, val);
793+
} ZEND_HASH_FOREACH_END();
797794
}
798795

799796
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
@@ -895,6 +892,7 @@ ZEND_API void zend_call_known_function(
895892
fci.retval = retval_ptr ? retval_ptr : &retval;
896893
fci.param_count = param_count;
897894
fci.params = params;
895+
fci.named_params = NULL;
898896
fci.no_separation = 1;
899897
ZVAL_UNDEF(&fci.function_name); /* Unused */
900898

ext/reflection/php_reflection.c

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1834,6 +1834,7 @@ ZEND_METHOD(ReflectionFunction, invoke)
18341834
fci.retval = &retval;
18351835
fci.param_count = num_args;
18361836
fci.params = params;
1837+
fci.named_params = NULL;
18371838
fci.no_separation = 1;
18381839

18391840
fcc.function_handler = fptr;
@@ -1897,6 +1898,7 @@ ZEND_METHOD(ReflectionFunction, invokeArgs)
18971898
fci.retval = &retval;
18981899
fci.param_count = argc;
18991900
fci.params = params;
1901+
fci.named_params = NULL;
19001902
fci.no_separation = 1;
19011903

19021904
fcc.function_handler = fptr;
@@ -3261,6 +3263,7 @@ static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, int variadic)
32613263
fci.retval = &retval;
32623264
fci.param_count = argc;
32633265
fci.params = params;
3266+
fci.named_params = NULL;
32643267
fci.no_separation = 1;
32653268

32663269
fcc.function_handler = mptr;
@@ -6516,23 +6519,23 @@ static int call_attribute_constructor(zend_class_entry *ce, zend_object *obj, zv
65166519

65176520
{
65186521
zval retval;
6519-
zend_fcall_info_named fci_named;
6522+
zend_fcall_info fci;
65206523
zend_fcall_info_cache fcic;
65216524

6522-
fci_named.fci.size = sizeof(zend_fcall_info_named);
6523-
fci_named.fci.object = obj;
6524-
fci_named.fci.retval = &retval;
6525-
fci_named.fci.param_count = argc;
6526-
fci_named.fci.params = args;
6527-
fci_named.fci.no_separation = 1;
6528-
fci_named.named_params = named_params;
6529-
ZVAL_UNDEF(&fci_named.fci.function_name); /* Unused */
6525+
fci.size = sizeof(zend_fcall_info);
6526+
fci.object = obj;
6527+
fci.retval = &retval;
6528+
fci.param_count = argc;
6529+
fci.params = args;
6530+
fci.no_separation = 1;
6531+
fci.named_params = named_params;
6532+
ZVAL_UNDEF(&fci.function_name); /* Unused */
65306533

65316534
fcic.function_handler = ctor;
65326535
fcic.object = obj;
65336536
fcic.called_scope = obj->ce;
65346537

6535-
zend_call_function(&fci_named.fci, &fcic);
6538+
zend_call_function(&fci, &fcic);
65366539
}
65376540

65386541
if (EG(exception)) {

ext/standard/basic_functions.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1570,7 +1570,7 @@ PHP_FUNCTION(call_user_func)
15701570

15711571
ZEND_PARSE_PARAMETERS_START(1, -1)
15721572
Z_PARAM_FUNC(fci, fci_cache)
1573-
Z_PARAM_VARIADIC('*', fci.params, fci.param_count)
1573+
Z_PARAM_VARIADIC_WITH_NAMED(fci.params, fci.param_count, fci.named_params)
15741574
ZEND_PARSE_PARAMETERS_END();
15751575

15761576
fci.retval = &retval;

0 commit comments

Comments
 (0)