Fragsworth
Fragsworth

Reputation: 35497

How can I convert a PHP function's parameter list to an associative array?

I want to convert the arguments to a function into an associative array with keys equal to the parameter variable names, and values equal to the parameter values.

PHP:

function my_function($a, $b, $c) {

    // <--- magic goes here to create the $params array

    var_dump($params['a'] === $a); // Should result in bool(true)
    var_dump($params['b'] === $b); // Should result in bool(true)
    var_dump($params['c'] === $c); // Should result in bool(true)
}

How can I do this?

Upvotes: 10

Views: 8568

Answers (5)

PHP 8+ named arguments

class User
{
    private string $email;
    private string $password;
    public string $firstName;
    protected string $lastName;

    public function __construct(...$arguments)
    {

        setterObject($this, ...$arguments);

        var_dump('email: ' . $this->email);
        var_dump('password: ' . $this->password);
        var_dump($this->firstName);
        var_dump($this->lastName);


    }
}

new User(email:'[email protected]', password: '#@some@password@_', firstName: 'firstName', lastName: 'lastName');

function setterObject(object $obj, mixed ...$arguments)
{
    $args = get_defined_vars()['arguments'];
    //just named arguments
    if (count(array_filter(array_keys($args), 'is_string')) ===count($args) ) {
        array_map(function ($prop) use ($obj,$args ) {
            $prop->setAccessible(true);
            if(!is_null($args[$prop->getName()])) {
                $prop->setValue($obj, $args[$prop->getName()]);
            }
        }, (new ReflectionObject($obj))->getProperties());
    }else{
        throw new Exception('the object was not initialized');
    }
}

Upvotes: 0

bishop
bishop

Reputation: 39414

As has been suggested, but not implemented: you can use Reflection to gather the parameter names, then associate those with the values:

function args_to_assoc_array($function, $args) {                                 
    if (false === strpos($function, '::')) {                                     
        $reflection = new ReflectionFunction($function);                         
    } else {                                                                     
        $reflection = new ReflectionMethod(...explode('::', $function));         
    }                                                                            
    $assoc = [];                                                                 
    foreach ($reflection->getParameters() as $i => $parameter) {                 
        $assoc[$parameter->getName()] = $args[$i];                               
    }                                                                            
    return $assoc;                                                               
}                                                                                

Then you can call this in the same way, whether in a function or a method:

function f($x, $y) { return args_to_assoc_array(__METHOD__, func_get_args()); }
class A {                                                                     
    function m($z) { return args_to_assoc_array(__METHOD__, func_get_args()); }
}                                                                             
var_dump(f(7, 2), (new A)->m(4));                                             

which outputs:

array(2) {
  ["x"]=>
  int(7)
  ["y"]=>
  int(2)
}
array(1) {
  ["z"]=>
  int(4)
}

I've not timed it, but I strongly suspect this is much much slower than using compact.

Upvotes: 1

Michael M
Michael M

Reputation: 8753

I upvoted @nickf's answer but would like to add that that compact() is also a great way to instantiate a model using a ctor:

class User {
    public $email;
    public $password;
    public $firstName;
    public $lastName;

    public function __construct ( $email, $password, $firstName, $lastName )
    {
        foreach ( compact( array_keys( (array)$this )) as $k => $v )
            $this->$k = $v;
    }
}

Just make sure that the params have the exact same spelling as the fields.

Upvotes: 4

Sandeep Shetty
Sandeep Shetty

Reputation: 1250

get_defined_vars() is what you need if no other vars are defined before its called inside the function (you can ensure this by making it the first thing you do inside the function).

function my_function($a, $b, $c) {

    $params = get_defined_vars(); // <--- create the $params array

    var_dump($params['a'] === $a); // results in bool(true)
    var_dump($params['b'] === $b); // results in bool(true)
    var_dump($params['c'] === $c); // results in bool(true)
}

Upvotes: 11

nickf
nickf

Reputation: 546075

The you can do this using compact:

function myFunc($a, $b, $c) {
    $params = compact('a', 'b', 'c');
    // ...
}

Or, get_defined_vars() will give you an associative array of all the variables defined in that scope, which would work, but I think this might also include $_POST, $_GET, etc...

Otherwise, you can use func_get_args to get a list of all the arguments passed to the function. This is not associative though, since it is only data which is passed (that is, there's no variable names). This also lets you have any number of arguments in your function.

Or, just specify one argument, which is an array:

function myFunc($params) {

}

compact() seems to be closest to what you're after though.

Upvotes: 12

Related Questions