Which is cleaner: a constructor with many parameters or many setters after construction? I'm trying to work out which is cleaner, having a large constructor or having to use many setters on a new object before doing some work with it.

Large constructor:

&lt;?php
class PathGeneratorWithBigConstructor {
  //...

  public function __construct($base_directories, $paths, $filename) {
    $this-&gt;base_directories = $base_directories;
    $this-&gt;paths = $paths;
    $this-&gt;filename = $filename;
  }

  //...
}

// Must pass the parameters in the correct order
$path_generator = new PathGeneratorWithBigConstructor($base_directories, $paths, $filename);


Many setters:

&lt;?php
class PathGeneratorWithSetters {
  //...

  public function set_base_directories($base_directories) {
    $this-&gt;base_directories = $base_directories;
  }

  public function set_paths($paths) {
    $this-&gt;paths = $paths;
  }

  public function set_filename($filename) {
    $this-&gt;filename = $filename;
  }

  //...
}

$path_generator = new PathGeneratorWithSetters;

// These can go in any order
$path_generator-&gt;set_paths($paths);
$path_generator-&gt;set_filename($filename);
$path_generator-&gt;set_base_directories($base_directories);


I'm trying to follow Robert "Uncle Bob" Martin's advice in Clean Code where he recommends against having too many parameters in a method. He states on page 40:


  Function Arguments
  
  The ideal number of arguments for a function is
  zero (niladic). Next comes one (monadic), followed
  closely by two (dyadic). Three arguments (triadic)
  should be avoided where possible. More than three
  (polyadic) requires very special justification—and
  then shouldn’t be used anyway.
  
  Arguments are hard. They take a lot of conceptual
  power. …


Obviously, I can't quote the whole section here, and if you disagree with his opinion, I'd advise familiarising yourself with the rest of his argument before posting a reply. He goes into greater detail over the next 3-4 pages which I can't summarise here because he has already written the appropriate amount of text on the subject. I do reference his ideas in the following paragraphs which is again why I recommend being familiar with his full opinion before replying.

In the class with the constructor, it's not obvious what order the parameters should go in (no natural ordering - page 42). You can't give a hint to the programmer with the method's name because it's the constructor, which should succinctly describe the object, not the order of its construction parameters (encode the names of the arguments into the function name - page 43).

With the constructor, an error will occur when the object is created if there are too few parameters. With the setters, an error will still occur later if each property is not set correctly, which is also the case for the constructor, so no clear advantage either way. Some IDEs will warn the programmer if the method signature doesn't match, while they can't warn about missing setters.

The parameters in this case can't be combined into an sensible object, because PathGenerator is the sensible object! $base_directories, $paths &amp; $filename don't have a logical grouping (reduce the number of arguments by creating objects out of them - page 43).

The class with the setters seems like a lot of work. It also seems too easy to miss one of the setters before trying to get it to do some work. However, reading the code that uses the setter class, it's obvious what it does, much more so than the large constructor version!

The third option, passing in a $parameters object/array, as I've seen recommended elsewhere, seems to combine the worst of both styles: extra work is needed to construct the object and it's easy to miss a parameter.

My goal is that the code should be easy to maintain (therefore also easy to understand) and easy to use. Which of the two styles is cleaner?
Where do you want to validate the parameters?


If the parameters are passed inside the constructor (either as multiple parameters or as a structure), the constructor can check all of them and throw an exception if something is missing/off. That way, the other methods of the class can assume they are valid. 
If the parameters are passed using setters, then every method needs to check if all the required values are present and valid. If the code runs in a multithreaded context, then there's additional protections needed as a value can change unexpectedly inside a method call if a setter is called from a different thread.