18

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);
apaderno
  • 28,547
  • 16
  • 75
  • 90
randomizer
  • 1,619
  • 3
  • 15
  • 31
  • Why not simply make your database object a singleton? – Matthemattics Nov 07 '12 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. – GolezTrol Nov 07 '12 at 14:02
  • 2
    @Lübnah [because Singletons suck?](http://stackoverflow.com/questions/4595964/who-needs-singletons/4596323#4596323) – Gordon Nov 07 '12 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. – Matthemattics Nov 07 '12 at 14:32
  • 1
    @Lübnah they are objective if you click the link – Gordon Nov 07 '12 at 14:37
  • @GolezTrol Well yes, of course. You're talking about making a Model object a la MVC-style. The Model superclass (or interface) still needs to connect to a database, though. Using a singleton (or singleton-like) pattern makes life easier because you don't need to pass around references to your DB instance whenever you want to instantiate a Model-inheriting class. Your DB instance is simply abstracted behind DB::getInstance(). – Matthemattics Nov 07 '12 at 14:37
  • @Gordon Of course I clicked the link - I'm not nearly that spiteful. I'm also not at all convinced by your 2nd argument. Basically, you offer no reasoning against simply injecting your dependencies via an abstracted Singleton, as that eliminates the need to pass them via constructor arguments (which is just obnoxious). No, it's not a "pure" Singleton, but it IS still a use of the Singleton pattern. – Matthemattics Nov 07 '12 at 14:47
  • @Lübnah I consider the "normal" way to use dependencies to inject them, so I'd need reasoning for *not* doing that. Also, passing ctor arguments is obnoxious? Why? – Gordon Nov 07 '12 at 14:50
  • @Lübnah If DB:getInstance() would return a database object, you may still want to use interfaces to enforce the implementation of certain methods by that instance. Having a common ancestor just isn't always the solution, and it doesn't necessarily make things easier, at least not in this case. It's like suggesting to eat a pear if someone asks whether or not to peel apples. – GolezTrol Nov 07 '12 at 14:56
  • @Gordon Because now you have to keep track of one or more dependency instances whenever you want to instantiate a Model! The most fundamental rule of CSE is if you're doing something repeatedly, abstract it out (and do it just once). Singleton offers a way to do just that. – Matthemattics Nov 07 '12 at 14:57
  • @GolezTrol Perhaps. I'm not saying it's universally appropriate. Putting $db behind DB:getInstance() does offer some pros. That's really all I'm trying to point out. – Matthemattics Nov 07 '12 at 15:00
  • @Lübnah I am sorry but I cannot follow you. There is nothing DRY about a Singleton. You dont need a Singleton to [create just once and only once](http://butunclebob.com/ArticleS.UncleBob.SingletonVsJustCreateOne). – Gordon Nov 07 '12 at 15:13
  • @Gordon DI actually violates DRY, if you must pass the same dependencies for each instantiation. A Singleton can provide (i) a single point of reference to an object, & (ii) a way to ensure that said object is instantiated -at all- upon referencing it. Thus, if the Database is a Singleton, instantiation can be postponed until it's actually referenced - e.g., until it's needed within the constructor. That's just one use case - surely there are more. Ergo, I don't subscribe to the "there is never a reason to use X pattern" style of reasoning. It's simply faulty. – Matthemattics Nov 07 '12 at 18:44
  • @Lübnah The point of a Singleton is to *ensure/enforce* instance singularity *and* provide a global access point. I cannot think of a situation in PHP where you would need that or where the price of tight coupling, bad maintainability, global state, hidden dependencies and single responsibility violations would outweigh the benefit. You certainly don't need a Singleton to defer object instantiation. For that, you can simply use a Factory. – Gordon Nov 07 '12 at 18:58
  • @Gordon I get what you're saying, & I don't necessarily disagree with your points. However, consider the simple situation. One needs a global access point, intends to instantiate just once, & wants to defer instantiation. Singleton is the lightest solution. Yes, that's a narrow use-case, but sometimes that's all one wants. – Matthemattics Nov 12 '12 at 14:04

7 Answers7

27

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.

DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
Gordon
  • 312,688
  • 75
  • 539
  • 559
13

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);
}
fd8s0
  • 1,897
  • 1
  • 15
  • 29
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.

Jon Hulka
  • 1,259
  • 10
  • 15
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() {
        //...
    }
}
omarjebari
  • 4,861
  • 3
  • 34
  • 32
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.

GolezTrol
  • 114,394
  • 18
  • 182
  • 210
0

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

  • 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](/help/how-to-answer). – Community Mar 20 '23 at 16:26
-4

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

Echilon
  • 10,064
  • 33
  • 131
  • 217
Oxi
  • 2,918
  • 17
  • 28