21

I'm having some issues thinking out a good structure to build my classes and objects. In the code below I make use of an interface to define my class methods, but I also want to pass a database connection to my constructor so the class had this connection to work with. Is it correct as I coded it below that the constructor is placed within my class and the methods in my interface?

interface IDataItem
{
    public function saveItem(Item $theItem);
}

class DataItem implements IDataItem
{
    public function __construct(Database $database) 
    { 
        $this->database = $database;
    }

    public function saveItem(Item $item) 
    {       
        //save the item
    }
}

$db = new Database(); //from a database class
$dataItem = new DataItem($db);          
$dataItem->saveItem($anItem);
15
  • Why not simply make your database object a singleton? Commented Nov 7, 2012 at 13:49
  • 3
    @Lübnah By making database object implement an interface, you can create a database-agnostic application that just uses the interface methods to store data, not knowing which data object instance is actually created. Commented Nov 7, 2012 at 14:02
  • 2
    @Lübnah because Singletons suck? Commented Nov 7, 2012 at 14:15
  • 3
    @Gordon Sigh… keep your arguments objective. I'm sure you have some valid points, but your opinionated & confrontational presentation unnecessarily obfuscates them. Commented Nov 7, 2012 at 14:32
  • 1
    @Lübnah they are objective if you click the link Commented Nov 7, 2012 at 14:37

7 Answers 7

29

While it is technically possible to add the constructor to the Interface, Interfaces should not define the constructor because that would be an implementation detail of an implementing class. An Interface should just define the public API other collaborators can call upon. That is, they should not enforce a particular implementation.

If you'd put a constructor asking for a database connection in the Interface, you'd limit the concrete classes to the dependencies in the constructor signature. If a concrete class implementing the Interface needs different (because it's saving to a Webservice) or additional (maybe a Logger) dependency you cannot make that work with your Interface.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, I had forgotten the explicit Item declaration in the Interface. The original post has been edited
This should be the accepted answer as of 2019-07-26
14

I don't personally think you should put the constructor in the interface because you'd never create a new object by calling the constructor without being aware of which implementation you're using.

There is a mistake in your code, the method in an interface cannot have an implementation, it needs to be just a declaration, like this

interface IDataItem
{
    public function saveItem($theItem);
}

2 Comments

Yes I'm sorry, that was a typo indeed, fixed it in the original post.
@randomizer, I am sorry, but just in case, even considering the 2012, the parameter name is also different (theItem vs item), which is possible (being "compatible") but normally invalid - the implementation should match the one defined in an interface.
9

This is a bit off the topic, but I think it highlights a case where it might be useful to have the constructor defined in the interface.

It is possible to instantiate an object without knowing its class. Here is a simple example:

interface Animal
{
    public function __construct($name);
    public function speak();
    public function getName();
}

class Cat implements Animal
{
    protected $name=null;
    public function __construct($name){ $this->name=$name; }
    public function speak(){ echo 'meow'; }
    public function getName(){ return $this->name;}
}

class Dog implements Animal
{
    protected $name=null;
    public function __construct($name){ $this->name=$name; }
    public function speak(){ echo 'woof'; }
    public function getName(){ return $this->name;}
}

$animals=Array(array('name'=>'Felix','type'=>'Cat'),array('name'=>'Fido','type'=>'Dog'));

foreach($animals as $a)
{
    $theAnimal=new $a['type']($a['name']);
    echo '<p>speak, '.$theAnimal->getName().'</p><p>';
    $theAnimal->speak();
    echo '</p>';
}

I've used something like this for url routing, to match urls to their top-level controllers.

Comments

6

According to the PHP documentation:

"Note that it is possible to declare a constructor in an interface, what can be useful in some contexts, e.g. for use by factories."

The point is that a constructor doesn't have to be defined with concrete classes but can be defined with interfaces, eg:

interface TestInterface {
    public function __construct(interfaceA, interfaceB);
}

Then the class implementing TestInterface defines its constructor with concrete implementations of interfaceA and interfaceB:

class Test implements TestInterface {
    public function __construct(testA, testB);
}

Where testA may be something like:

class testA implements interfaceA {
    public function doStuff() {
        //...
    }
}

Comments

2

Interfaces are just a contract to enforce that classes that may be unrelated will all implement the same methods.

Since you have to explicitly know the class when constructing it, it is useless to put the constructor in the interface. You will never call the constructor through the interface. Your current solution is correct.

Comments

1

If you think you need a constructor in an interface, perhaps consider using an abstract class for it.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
-4

Make a variable to hold the db handle in your class.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.