rfc:func_get_args_by_name

PHP RFC: Add func_get_args_by_name()

Introduction

This RFC proposes adding a new func_get_args_by_name() function that returns all function arguments with their parameter names preserved as array keys, unlike func_get_args() which returns only positional arguments.

<?php
function greet(string $name, int $age, ...$extra): array {
    return func_get_args_by_name();
}
 
var_dump(greet('Alice', 30, 'foo', 'bar'));
// array(4) {
//   ["name"]=> string(5) "Alice"
//   ["age"]=> int(30)
//   [2]=> string(3) "foo"
//   [3]=> string(3) "bar"
// }
?>

With named arguments becoming widely used since PHP 8.0, this function provides a straightforward way to introspect function calls while preserving argument names.

Motivation

Currently, there is no built-in way to retrieve function arguments with their parameter names. The existing func_get_args() returns only positional values, and func_get_arg() requires knowing the position index. The only way to get named arguments is through reflection, which is verbose:

<?php
function example($a, $b) {
    $reflection = new ReflectionFunction(__FUNCTION__);
    $params = $reflection->getParameters();
    $args = func_get_args();
    $result = [];
    foreach ($params as $i => $param) {
        if (isset($args[$i])) {
            $result[$param->getName()] = $args[$i];
        }
    }
    return $result;
}
?>

The proposed func_get_args_by_name() eliminates this complexity and makes argument introspection straightforward.

Proposal

Add a new func_get_args_by_name() function to PHP. This function:

  • Returns an array where keys are parameter names and values are the passed arguments
  • Includes variadic arguments, which receive numeric keys if passed positionally, or named keys if passed via spread operator

Key Difference from func_get_args():

When using the spread operator with named arguments, func_get_args_by_name() captures extra named arguments that func_get_args() discards:

<?php
function process(string $name, int $age, ...$extra) {
    return func_get_args();
}
 
var_dump(process(...[
    'age' => 30,
    'name' => 'John',
    'extra' => 'data',
]));
// array(2) {
//   [0]=> string(4) "John"
//   [1]=> int(30)
// }
// 'extra' is missing
 
function process_named(string $name, int $age, ...$extra) {
    return func_get_args_by_name();
}
 
var_dump(process_named(...[
    'age' => 30,
    'name' => 'John',
    'extra' => 'data',
]));
// array(3) {
//   ["name"]=> string(4) "John"
//   ["age"]=> int(30)
//   ["extra"]=> string(4) "data"
// }
?>

Considered alternative

Another approach would be to add a new argument to func_get_args(), like bool $assoc = false. However:

  • Adding a boolean flag is usually considered being against single responsibility principle
  • Setting the flag to true would change the function core behavior (because of the support of variadic arguments), which would also be against the principle of least astonishment

For these reasons, this alternative was rejected.

Backward Incompatible Changes

This RFC introduces a new function without modifying existing functionality. Userland code declaring a function in the global namespace using this name would not work anymore, but a quick search on GitHub with the proposed function name revealed no result.

Proposed PHP Version

PHP 8.6 (next minor version)

Voting Choices

This is a simple yes/no vote requiring a 2/3 majority.

Add func_get_args_by_name() to PHP 8.6?
Real name Yes No Abstain
Final result: 0 0 0
This poll has been closed.

Vote will start on [TBD] and end on [TBD].

References

rfc/func_get_args_by_name.txt · Last modified: by alexandredaubois