php - Never instantiate objects in the constructor?

423

Is it bad instantiating objects in the constructor like this below?

class Foo
{
    public function fooMethod() {
        return 'foo method';
    } 
}

class Too
{
    public function tooMethod() {
        return 'too method';
    } 
}

class Boo
{
    public $foo;
    public $too;

    public function __construct()
    {
        $this->foo = new Foo();
        $this->too = new Too();
    }
}

If so, how bad can it be? How should it be done properly?

504

Answer

Solution:

Manually instantiating classes inside another class creates implicit dependencies, which are quite hard to maintain - you will have a hard time detecting what needs to be changed if you ever need to change thoseFoo andToo classes.

So, a better way of managing dependencies is:

class Foo
{
    private $_bar;

    function __construct(Bar $bar)
    {
         $this->_bar = $bar;
    }
}

This way, your object dependency is explicit. Another advantage of doing this, is that some PHP frameworks, (Laravel, Zend, Symfony), allow for an automatic dependency resolution. It means, that you don't instantiate your object manually, only via some sort of factory - like this (Laravel):

$foo = App::make('Foo');

And anApp factory automatically detects yourFoo class dependencies with some reflection magic and injects them appropriately. Other frameworks have similar capabilities, too.

Also, there are some general principles in OOP, calledSOLID which help to develop better OOP design. One of them -D, stands forDependency Inversion. What it means, is that you should avoidhard dependencies, like in your code. Instead, bothFoo andBar classes should depend on aninterface, like this:

interface BarInterface
{
    function doBar();
}

class Bar implements BarInterface
{
    function doBar()
    {
        print "Doing BAR";
    }
}

class Foo
{
    /**
     * @var BarInterface
     */
    private $bar;

    function __construct(BarInterface $bar)
    {

        $this->bar = $bar;
    }
}

Now, if you ever need to change thatBar class with something else, all hell won't break loose, if your replacement also implements thatBarInterface.

803

Answer

Solution:

It's not inherently bad.

The downside is that it decreases the "testability" of your class, simply becauseBoo is now dependent on the existenceFoo andToo.

355

Answer

Solution:

This depends on the size of your project.

On large projects, or long term projects, it should be changed slightly.

Ideally, you would refactor it implement Dependency Injection pattern, and maybe use a Factory to instantiate it.

Some sample code:

interface FooInterface { function fooMethod(); } 
class Foo implements FooInterface { function fooMethod(){return 'Foo';} }

interface TooInterface { function tooMethod(); } 
class Too implements FooInterface { function tooMethod(){return 'Too';} }

class Boo
{
    public $foo;
    public $too;

    public function __construct(FooInterface $foo, TooInterface $boo)
    {
        $this->foo = $foo;
        $this->too = $boo;
    }
}

class BooFactory
{
    public static function create()
    {
        return new Boo(new Foo, new Too);
    }
}
95

Answer

Solution:

It depends of your requirement and the classes. Let's says that every call to the constructor of Foo/Too you will execute a huge query to the database to get data, in that scenario I would opt to use lazy instantiation.

Of course, it's a good practice to initialize your properties on the constructor, but on real life performance could your enemy.

Example:

class Boo {
   private $foo = null;
   private $too = null;
   public function __construct() {
      //Do something else
   }
   public function getFoo() {
      if (is_null($this->foo)) {
         $this->foo = new Foo();
      }
      return $this->foo;
   }
   public function getToo() {
      if (is_null($this->too)) {
         $this->too = new Too();
      }
      return $this->too;
   }
   public function aMethodThatUsesFoo() {
      $foo = $this->getFoo();
      $foo->fooMethod();
   }
   public function aMethodThatDoesntUsesFoo() {
      echo "Hello!, I don't need foo or too to execute this method";
   }
}

if you use this class only to executeaMethodThatDoesntUsesFoo(), it will never call the constructors of Foo/Too.

$boo = new Boo();
$boo->aMethodThatDoesntUsesFoo();

if you will only executeaMethodThatUsesFoo(), it will only instantiateFoo

$boo = new Boo();
$boo->aMethodThatUsesFoo();

You can do this by static methods as well.

People are also looking for solutions to the problem: php - wordpress .htaccess rewrite url

Source

Didn't find the answer?

Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.

Ask a Question

Write quick answer

Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.

Similar questions

Find the answer in similar questions on our website.