Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

PHP

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Trying to understand interfaces.

So I understand the basic concept. Interfaces serve as a contract for all implementing classes. They contain a ruleset of sorts with no actual logic.

Is its purpose purely organizational and non-functional?

Looking at it through noob glasses, it just looks like more code. How does it help with scalability other than providing a reminder of what methods to use? If you have to change or modify these methods, you still have to go into each individual class to change them.

3 Answers

I think the idea of "less code" is not something that is necessarily the point of interfaces, but rather it is to have consistent functionality throughout your application. We want to make sure that all database providers that implement the interface declare the required methods for our application. Below we are going to do a simply query with a result:

// Somewhere in our main application
$dbResults = $dataProvider->fetch("SELECT * FROM SOME_TABLE");

In this example, $dataProvider can be any kind of provider - SQLIte, MySQL, MongoDB. Our interface looks like this:

interface DatabaseInterface
{
    public function fetch($sql);
}

So in order for our database provider classes to function properly in our application they must implement the DatabaseInterface and hence we know that each provider will certainly have a fetch() method. If our provider was for a MongoDB it could look like this:

class MongoProvider implements DatabaseInterface {
    public function fetch($sql) {
       $dbResults = [];
        // Code that fetches a query result in MongoDB
        return $dbResults;
    }
}

If we did not use an interface then we have no requirements on how our database provider should work. Instead of fetch(), we could call the method runThisSQL().

class MongoProvider {
    public function runThisSQL($sql) {
       $dbResults = [];
        // Code that fetches a query result in MongoDB
        return $dbResults;
    }
}

The problem here is that now we can't just plugin our database provider into our application because all the calls our application makes requires fetch(). Our application does not know, nor care what kind of database provider we use, the application just expects the database provider to have a basic set of methods that are defined in our interface. So should we go through our code and make exceptions for MongoDB? Every time we see a fetch() call, check if it is MongoDB and if so, run the method runThisSQL()? Before you know it, we have a bunch of code built to just handle each kind of database we encounter and it can get very messy. Let us not worry about that and let the database providers handle the unique circumstances regarding retrieving data and providing it to us. Our application only needs to ensure that it can call basic methods such as fetch() that it knows a database provider must implement. This creates less coupling in our code and gives us the opportunity to be more flexible.

Lastly, remember you can create abstract classes that work like an interface which will require the extending class to implement the methods, but you can alsp define methods and their functionality which will be inherited to the subclass. Which in the end will give you the best of both worlds.

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Awesome. That really helps to clear it up. I think my issue is I haven't made anything to a scale yet where using interfaces is that beneficial. Much appreciated.

Let's say we have an application that reads information from a database. Right now we haven't decided what database to use - MySQL, SQLIte, Oracle, Postgres, SQL Server, ect. The first thing we do is create an interface that defines all the methods we would call to interact with our database such as fetch(), insert(), delete(), and so on. We will call this interface DatabaseInterface. Our main code would call the methods we defined in our interface to interact with our data. If we decided to use MySQL as our database, then we can create a MySQLProvider class and have it implement the methods we defined in our DatabaseInterface.

Later, we decided that we wanted to support SQLite, so we create a SQLiteProvider class and it implements the DatabaseInterface we created as well. Now, it doesn't matter what backend we have because as long as our data provider classes implements the methods in our interface we know the code will work. The benefit to this is that now we can create support in our code for various backends without having to modify it in every place a database call is made. We simply create a new data provider class that implements the DatabaseInterface we created. In the long run this saves us from writing a lot of code and makes our application more flexible.

Lastly, if you wanted to provide methods in your interface that can be inherited from classes that extend it, you can create instead an Abstract Class.

Łukasz Czuliński
Łukasz Czuliński
8,646 Points

Hi Miguel, thanks a lot for the reply. I know I'm missing some obvious key point here because there's still a bit I'm unclear of.

The benefit to this is that now we can create support in our code for various backends without having to modify it in every >place a database call is made. We simply create a new data provider class that implements the DatabaseInterface we created. In >the long run this saves us from writing a lot of code and makes our application more flexible.

The way I've understood it so far, implementing a class means that class simply follows a contract defined in the interface. You still have to write out all the logic in each provider class. Because Interfaces are non-functional, how does it save us from writing code?

Let's say we start with SQL, then decide to switch to MongoDB so our code is kinda like this:

interface DatabaseInterface{
    //query methods/properties names only
}

class SqlProvider implements DatabaseInterface{
    //query methods/properties + logic
}

class MongoProvider implements DatabaseInterface{
    //query methods/properties + logic
}

How is this any different? I see less code, since nothing is actually inherited from the interface.

class SqlProvider{
    //query methods/properties + logic
}

class MongoProvider{
    //query methods/properties + logic
}