2

Suppose i have a class like this:

class Foo{
    public function bar($p,$p2=null,$p3=null){
        //...
    }
}

Sometimes i need to call it passing just the first and third params. The problem is that i would have to put the second param, passing anything, just to reach the third.

I could create private properties and setters methods for the optionals params and remove them from the method signature.

Is this a good practice? Or it's better use __call or func_get_args instead?

Sources that i've read in S.O.:

and in the manual:

Community
  • 1
  • 1
Rafael Barros
  • 1,043
  • 18
  • 25

2 Answers2

2

I could create private properties and setters methods for the optionals params and remove them from the method signature.

It would be a very bad idea to do this if the reason is that you want them to get out of the way.

What is a parameter and what is a property are decisions making up the design of the class, so swapping one for the other should be made only after looking at the big picture (as any other design decision). Don't make this kind of change because you don't like how one specific call site for one specific method reads.

We can't tell if it makes sense for the parameter to be a property instead, so for the remainder I 'm going to assume that it does not. What are the options in this case?

Option #1: Refactor

  • Does it make sense to have two optional parameters on this method?
  • Do you usually leave out one (or both) of them when calling it?

If the answer to these questions is "yes", that could be an indication that the method operates in different modes depending on the arguments. In this case it can make sense to break out the modal behavior into separate methods that have simplified signatures.

Option #2: Bundle of properties

  • Does this method have a lot of parameters with sensible defaults?
  • Do you usually provide only a few (or none) of these on a typical call?

If the answer to these questions is "yes", then you can make the method accept an array as its last argument and use that as a container of "misc options".

This approach has the (big!) drawback that these options are not being advertised through the method signature anymore, but it can make sense if there are sensible defaults that you won't be touching 90% of the time.

Option #3: Fluent interface

If there are a lot of options that could be specified then creating a fluent interface can make sense, but this is a big change and one that should not be made unless there are additional arguments going for it (e.g. if composability is desired). You could view a fluent interface as the better-engineered version of turning arguments into properties.

Writing a fluent interface involves a new class that encapsulates all the arguments that could possibly go into a function call; the class has one method for each argument and one or more methods that use these arguments to do work. A fluent interface call site would look like

$foo->bar()->color('red')->type('widget')->execute();

Here $foo->bar() returns an instance of the encapsulating class, color and type are methods on that class that set properties and execute reads these properties and performs the actual work.

Jon
  • 428,835
  • 81
  • 738
  • 806
1

How could you define which argument is the second or the third with funct_get_args or call ? It's only possible if they have different types.

In my opinion, if you want a powerfull way to work with many arguments which may be optionals use a container like a bundle object (generic or specific for your function) or, more friendly, an associative array.

flchaux
  • 100
  • 1
  • 13