Brett
Brett

Reputation: 20049

Do interfaces just DESCRIBE what implemenations need to do?

I'm just learning about PHP's interfaces as I have never really used them before, but as I understand it they are only a interface, as they are called, to kind of uphold how classes that implement them are structured?

So for example, if you wanted to make two different classes for two different databases you could do:

class mysql {

    public function connect() {
        // code here
    }

    public function getData() {
        // code here
    }

}

class mongoDB {

    public function connect() {
        // code here
    }

    public function getData() {
        // code here
    }

}

...and that would technically be the same as:

interface database {

        public function connect() {

        }

        public function getData() {

        }   

}

class mysql implements database {

    public function connect() {
        // code here
    }

    public function getData() {
        // code here
    }

}

class mongoDB implements database {

    public function connect() {
        // code here
    }

    public function getData() {
        // code here
    }

}

...am I right? It's just that using an interface it makes sure you don't go doing something like the below and hence not being able to change databases easily?

class mysql {

    public function connect_mysql() {
        // code here
    }

    public function getData() {
        // code here
    }

}

class mongoDB {

    public function connect_mongo() {
        // code here
    }

    public function getData() {
        // code here
    }

}

Is that pretty much the reasoning behind them?

Upvotes: 0

Views: 40

Answers (1)

deceze
deceze

Reputation: 522165

What the interface does is it standardises what your code can rely on, and at the same time decouples that from a specific implementation. Wow, that sounds complicated. It's easier to illustrate it from the perspective of a user of interfaces:

function (MyDatabaseInterface $db) {
    $db->connect();
    $db->getData();
}

Type hints are a big part of using interfaces. This function declares that its argument must be an instance of MyDatabaseInterface, in other words, any object that implements MyDatabaseInterface. It is entirely up to you what specific object that is, as long as it implements MyDatabaseInterface. And since in MyDatabaseInterface you have specified the methods connect() and getData(), you can be sure that any object being passed in has these methods and that you can call them.

The other way around, have a look at this function:

/**
 * @return MyDatabaseInterface
 */
function foo() {
   ...
}

It is irrelevant what this function does internally, but it declares that it will return an object of type MyDatabaseInterface, in other words some object that implements MyDatabaseInterface. When you call it, you know what you can rely on:

$bar = foo();
$bar->connect();
$bar->getData();

This function may return an instance of mysql or of mongoDB, it is none of your concern. You simply stick to what was declared in the interface and your code will work regardless of what specific object you get.

An interface literally defines the interface between code. It defines what methods code can safely call on other code, without tying down the specifics to specific classes. Your specific objects could define a ton more methods than are defined in the interface; an interface does not declare a class structure. A class could implement several interfaces at once, meaning it implements all the methods of all the interfaces; each individual interface would then just represent a subset of all the possible methods that could be called on an object.

You should describe specific "tasks" or "abilities" which can be accomplished in an interface, not "classes". It's a good sign if your interface names end with "-able", like Iterable. A class can then implement several interfaces and thereby describe all the things it "can do". You can then require function arguments with a certain "ability" at specific points, as shown in the example code above. This isolates and decouples parts of code from one another, which makes your code more flexible, reusable and adaptable to change.


For a useful real world scenario, imagine a larger development team which is working on a large project. There are several sub-teams, each responsible for a different part of the application. They all sit down together and come up with a general plan. At some point, the code of these separate teams needs to interact with each other. They can define these interfaces upfront:

  • "I'll need to call some method on your code that gives me the user credentials."
  • "OK, then you'll need to give me some object from which I can get the foobar."
  • "Then over here we'll have to talk to Joe's component to send the baz data."
  • ...

They can define the different methods they will need to talk to each other in an interface before any code has been written, then go off and do their own thing. They can rely on code which hasn't even been written yet, because they already decided on what the interface will look like. They can even substitute the real code with mock objects for the time being while Joe is still hammering out his real code, then simply switch it in later with whatever Joe comes up with. And all those techniques are useful even if you're just working by yourself.

Upvotes: 1

Related Questions