Home » Php » What are the best practices for passing multiple variables to a function using PHP

What are the best practices for passing multiple variables to a function using PHP

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a function that takes 5 parameters, and as the application grew we needed to add few more parameters which ended up in 9 parameters with 4 of them having default values.

I was wondering is it better to pass parameters like this or use an array?

I prefer to have it like this

fun(array(
     'par1' => 'x',
     'par2' => 'y',
     .....
    )
 )

Insted of

func($par1, $par2, $par3, ...);

What do you think?

How to&Answers:

Highly depends on the use case.

But here are some solutions to this problem.


Fixed Order

If the order is somewhat fixed and you never have a need to change it, then:

<?php

function fn($a1, $a2, $a3, $a4, $a5, $a6 = null, $a7 = "foo", $a8 = "bar", array $a9 = array()) {}

Pros

  • Self documenting
  • Type hinting
  • Default values

Cons

  • Fixed order

Array

If on the other hand the order is somewhat different all the time, use the array thingy.

<?php

function fn($a1, $a2, $a3, $a4, $a5, array $optional = array()) {}

fn("", "", "", "", "", array("arg9" => false));

Pros

  • Easy to use
  • No fixed order

Cons

  • Not self documenting
  • Costly to validate

Parameter Object

A parameter object is of course a valid solution as well, but impractical to handle:

<?php

class Args {

  public $arg5 = "foo";

  public $arg6 = "bar";

  public $arg7 = null;

  public $arg8 = array();

  public $arg9 = true;

}

function fn($arg1, $arg2, $arg3, $arg4, $arg5, \Args $optional = null) {}

// Now comes the impractical part.
$optional = new Args();
$optional->arg9 = false;
fn("", "", "", "", "", $optional);

Pros

  • Self documenting
  • No fixed order

Cons

  • Highly impractical
  • Costly to validate

Array to Parameter Object

You could mix the two approaches:

<?php

class Args {

  public $arg5 = "foo";

  public $arg6 = "bar";

  public $arg7 = null;

  public $arg8 = array();

  public $arg9 = true;

  public __construct($args) {
    foreach ($args as $property => $value) {
      $this->"set{$property}"($value);
    }
  }

  public function setArg5($value) {
    if (is_string($value) === false) {
      throw new \InvalidArgumentException;
    }
    $this->arg5 = $value;
  }

  // and so on ...

}

function fn($arg1, $arg2, $arg3, $arg4, $arg5, array $optional = null) {
  if (isset($optional)) {
    $optional = new Args($optional);
  }
  // ...
}

fn("", "", "", "", "", array("arg9" => false));

Pros

  • Easy validation
  • Separation of concern
  • Easy to pass along
  • Easy to handle
  • Possible to document the API

Cons

  • Still not possible to document it as good as the fixed args approach
  • Costly to validate

Variadics

There’s a new feature in PHP 5.6 that you might find useful, variadics:

<?php

function fn($a1, $a2, $a3, $a4, $a5, ...$optional) {}

Pros

  • Very fast
  • Allows to build special APIs (e.g. database prepared statement binding)

Cons

  • Not easily documented
  • Costly to validate

Named Parameters

And we might see named parameters in the future.

Answer:

You’re attacking the wrong problem.

Passing 9 parameters to a function is a clear code smell:

Too many parameters: a long list of parameters in a procedure or
function makes readability and code quality worse.

With that many parameters, there’s also a good chance that you violate:

Long method: a method, function, or procedure that has grown too
large.

Creating an arbitrary array that groups together those parameters won’t solve the real issue. It can make your code somewhat more readable and less vulberable to small problems like omitting a parameter ($arg1, $arg2, $arg4), but not a real solution.

What you should do instead:

Figure out why the function needs that many parameters, then fix that issue.

  • If the single function has too many reponsibilities: split it. You can do a single sequential split: One task after the another.
  • If multiple parameters can be aggregated to a single entity, create an object for it (eg: x and y coordinates can be merged to a point. a rectangle can be described by two opposite corner points). Try to create something reusable, so it’s sole purpose isn’t just to be able to pass arguments to this single function.

There are a lot of techniques, reading a good article/book about (oo) code refactoring can give you some hints.