10

I have lots of code like this in my constructors:-

function __construct($params) {

    $this->property = isset($params['property']) ? $params['property'] : default_val;

}

Is it better to do this rather than specify the default value in the property definition? i.e. public $property = default_val? Sometimes there is logic for the default value, and some default values are taken from other properties, which was why I was doing this in the constructor.

Should I be using setters so all the logic for default values is separated?

2 Answers 2

8

I've had this kind of philosophical debate with myself before. Here's where I stand most of the time although I realize this is an opinion-based answer:

One thing I see that might help answer the question is the passing of $params which may or may not have attributes/array members that are set.

Over the years I've come to this conclusion:

Avoid the passing of arrays.

Why? Well, there is no way to set or have sentinel values defined for optional passed arguments.

In other words, with the code you specified, you can't do something like this:

function __construct($arg1 = NULL, $arg2 = DEFAULT_VAL) {

    $this->arg1 = $arg1;

    $this->arg2 = $arg2;

}

$arg1 and $arg2 are optional arguments - if not passed they have NULL and DEFAULT_VAL respectively - no need to check explicitly.

Maybe this seems kind of arbitrary.

I think I get what you're trying to accomplish - the passing of a single reference as opposed to tons of arguments. This brings me to my next consclusion:

If not passing "atomic" variables (strings, integers, literals) then pass objects.

There are performance benefits here since passing objects is done by reference (although arrays I think are the roughly the same inside PHP).

So you might do something like:

function __construct(MyAwesomeObject $oArg) {

        $this->oArg = $oArg;

    }

The passed object argument would then be guaranteed to have "property1", "property2" albeit possibly with default values themselves.

Additionally, here you can type hint and a good IDE will correctly autosuggest code completion as well.

But we quickly realize we have a chicken and an egg thing going on: you're constructing an object with passed object arguments that themselves need constructing at some point.

So where does this leave us? Well, I've come to the conclusion that eventually all classes distill down to, for lack of a better term, "atomic" variables (strings, floats, doubles, ints, resources you get my point), and that I tend to try to construct all classes with those variable types or objects - but not arrays.

So did I answer your question? probably not exactly. But I hope I illustrated something useful albeit somewhat stylistic. I think the code is a bit cleaner, more readable, and less costly.

Now, this isn't to say you shouldn't sanitize your input. That's another discussion entirely.

Hope this helps.

1
  • 1
    It's a good point, and very handy for IDE prompts but there are far too many object properties to pass them all as parameters. If you have 7 arguments say 5 of which are optional you end up with things like new object($param1,-some default value so I can specify the next parameter-, $param3); and so you have your default values hard coded in several different places
    – rgvcorley
    Commented Apr 8, 2012 at 22:02
3

Although I tend to avoid passing arrays to a constructor, sometimes I find it necessary to process an incoming array value (such as for a class that reads values from a configuration file).

In a case like this, I will take advantage of PHP's array functions to ensure that I am working with exactly what I think I'm working with:

public function import( array $incoming )
{
  $defaults = array(
      'foo' => DEFAULT_FOO
    , 'bar' => DEFAULT_BAR
    ...
  );

  $values = array_merge($defaults, array_intersect_key($incoming, $defaults));

  ...
}

That last line uses array_merge() to overwrite any values in $defaults with their corresponding values from $incoming. I also use array_intersect_key() to ensure that the resulting array does not contain any extra keys that the class/method wouldn't know how to process.

2
  • Hello, What's the behavior if $defaults contains an array instead of simple variables ? Commented Sep 5, 2014 at 11:59
  • @PolDellaiera Look at array_merge_recursive.
    – user34530
    Commented Sep 5, 2014 at 12:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.