A Practical Demonstration of Interfaces vs. Abstract Classes in PHP

Breeze past this very common developer interview question

Casey McMullen
Jan 16, 2020 · 13 min read
Image for post
Image for post

I’ve been writing PHP code since 2008. Over that time I’ve built all sorts of applications for all sorts of purposes. When you write code for that long, you find yourself creating a library of tools, utilities, and snippets of code that you use over and over. After a while, you discover you’re reusing code you wrote years ago and now don’t remember how it works or why, or even if there might be a new and better way. Your old reliable code just does what it has always done and works, so you use it and don’t ask questions.

Recently, when someone asked me to explain the difference between an interface and an abstract class, I realized I couldn’t answer the question (at least not intelligently). Here I have been building these things for years and haven’t known how, or been required, to articulate the differences.

I started Googling this common question and discovered it gets very generic answers. I haven’t found anything but responses using sample code for Function1 and Function2 and some equally generic methods. In real life I write code for things like Customers and Orders and it would make more sense to me if the examples were a little more real as well.

So, I’ve decided to create this practical example of using abstract classes and interfaces. I’ve included some working code that you can access and experiment with yourself.

Let’s get started!

The Sample Code and Database Setup

All of the PHP code for this example can be found in the following Github repository. Feel free to download and use this code any way you want, without attribution.

https://github.com/crmcmullen/medium-interfaces-abstracts/

In addition, for this example, I’m going to use a MySQL server, set up in a Docker container, following the instructions in my article, “How to Run MySQL in a Docker Container on macOS with Persistent Local Data

For my demonstration I need a database, so I’ve installed the sample database from MySQL Tutorial.

If you’re going to try out my sample code, you should download and install the database from their website. It will create a database called classicmodels that contains the tables that we need.

Once you’ve done that, run the following MySQL script to create a database user that we’ll use in our example code to connect to the database.

Note: There are several lines in the snippet below, you can just copy all of them and run them in a single execution.

/*  Create DB user */USE `classicmodels`;CREATE USER 'classicmodelsUser'@'%' IDENTIFIED WITH mysql_native_password BY 'foobarPassword';CREATE USER 'classicmodelsUser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'foobarPassword';GRANT SELECT, INSERT, UPDATE, DELETE, EXECUTE ON classicmodels.* TO 'classicmodelsUser';

The Use Case

In this example, we’re going to query and display data from two database tables in the classicmodels MySQL database: the customers table and the orders table.

Therefore, I’m going to need to be able to connect to the database. The PHP code to do that will be identical for both tables (indeed for all tables) in the database, so I’m going to create an abstract class that all of my database classes can extend to connect to the database.

Then, I’m going to create database classes for each table that contain the functions and methods specific to each one. I want to make sure that all of the database classes I (or my team of developers) build follow the same rules. There are certain methods that are always required in my database classes. For example, every database class requires a function that inserts data, one that deletes data, and one that produces a list of records. So when my developers build database classes, I want to make sure these specific methods are always included, even if the code inside them might be a little different. To enforce this sort of “class blueprint” I will implement an interface to define the functions that must be included in all database classes.

To fulfill the requirements of this use case I’m first going to build the parts and pieces to query and display data from the customers table. That will include the following:

  • An abstract class called Data_Access that my “concrete” database classes can extend. It will provide the methods and functionality for connecting to the classicmodels database.
  • An interface class called Data_Interface which will define the functions which must be included in my concrete database classes.
  • A “concrete” database class called Customers which will contain the functions necessary for interacting with the customers table.
  • An index.php page that will be our landing page that instantiates our classes and retrieves and displays the customer data.

Once that’s done, we’ll come back and:

  • Add a page to display customer orders called customerOrders.php.
  • Create a concrete class called Orders which will contain all the functions necessary for interacting with the orders table and illuminate the power of abstract classes and interfaces.

The Abstract Class

An abstract class is a class that not only has the ability to define required methods for concrete classes, but can also provide an implementation of those methods. To use an abstract class, a concrete class must extend the abstract class which then makes all of the methods defined in the abstract available inside the concrete class.

To illustrate this, let’s begin by examining our Data_Access abstract class. In our example code, I’ve created a file called data_access.php. It has two functions in it: dbConnect and getResultSetArray.

In Image 1 below you can see we define Data_Access as an “abstract class” on line three. This enforces the idea that it’s an abstract class and therefore cannot be instantiated as a standalone class. It can only be extended. This is a rule of abstract classes that ensures it is treated as an abstract.

If we were to try to instantiate the Data_Access class as a standalone object:

$cDataAccess = new Data_Access;

It would throw the following error:

PHP Fatal error:  Uncaught Error: Cannot instantiate abstract class Data_Access ...
Image for post
Image for post
Image 1: Data_Access::dbConnect

Image 1 above shows the dbConnect function in Data_Access that performs the connection to the database.

Note: At the top of this function you can see I’m defining some variables for database credentials. Normally I don’t keep this kind of stuff in code, I would bring those credentials in from an INI file outside of the public web folder. But for this demonstration, it helps keep things simple.

The dbConnect function attempts to connect to the database and store that connection in a GLOBAL variable that will be available to share with other database classes during the life of the PHP page instantiating the class. If an error occurs, it is raised back to the calling function in an array.

Finally, in Image 2 below, we have the getResultSetArray function in Data_Access:

Image for post
Image for post
Image 2: Data_Access::getResultSetArray

The function getResultSetArray accepts a query string as a parameter and uses the established database connection to execute the query. It then places the results into an associative array and returns it back to the calling function. If an error occurs, that’s also raised to the calling function.

Note: The reason I return everything in the form of a response array, is to provide consistency to the calling functions. In doing so, my calling functions can know that the response is always going to come back in this form, pass or fail, with a response code, message, and any data results in an associative array called dataArray. This associative array is easily used in PHP or Javascript.

With Data_Access complete we now have an abstract class that can be extended by our concrete classes. It provides functions that implement code that can be shared by all of the classes. It’s not specific to any database or table (especially if you remove the hard-coded credentials in dbConnect), and therefore fulfills the requirements of an abstract class in PHP.

Now let’s take a look at an interface.

The Interface

Think of an interface as a template or contract for your concrete classes. In our example, we said we want all of our database classes to have three functions — one to insert a record, one to delete a record, and one to get a list of records.

I can enforce that rule across all of the database classes by creating an interface that contains the signature for all of those functions and then implementing that interface in my concrete classes.

Let’s look at our example in Image 3 below. I created a file called data_interface.php and added the signature of the required three functions and the parameters that they require.

Image for post
Image for post
Image 3: Data_Interface

Notice that none of the functions in the interface have a body. This is because, while interfaces can implement methods, they can’t implement functionality. That is to be provided by the implementing class.

All we’re doing with an interface is enforcing the expectation that classes implementing this interface will all have the same methods. There are some other benefits to interfaces that I’ll discuss in a bit.

Now let’s bring this together in our first concrete class.

The Customers Class

This simple concrete class is intended to be used as our gateway to the customers table in the database. It will contain all the functions necessary to interact with that table.

In Image 4 below, we see the Customers class in the file customers.php:

Image for post
Image for post
Image-4: Customers

In the Customers class we’re extending our abstract class Data_Access and implementing our interface Data_Interface. A concrete class can extend only one abstract class, but it can implement numerous interfaces. You merely separate your interfaces with a comma. We’ll demonstrate that shortly.

The Customers class has a constructor function that calls dbConnect and attempts a database connection. If it fails we have a not so graceful exit. Normally you would navigate to a visitor-friendly page explaining the issue.

Next, you see our three functions, and the required parameters if any, that are required by the interface: insertRecord, deleteRecord, and getList.

Because the interface enforces its implementation rule, if I tried to leave out one of the functions in Customers, for example insertRecord, and tried to instantiate it, we would receive a fatal error:

PHP Fatal error:  Class Customers contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Data_Interface::insertRecord)

The getList function requires a parameter variable. This is enforced by the Data_Interface we implemented. This is to ensure that the getList function, in all of the concrete classes that implement it, uses a filter parameter for the SELECT statement. In the case of our Customers list, we want all records, so we’ll include code that allows the value of zero to indicate All Customers in our query. Otherwise, you could pass getList a specific customer number and get that single record back. A list of one is still a valid list!

The function goes on to create a query string and then calls the getResultSetArray function that became available on extending the Data_Access abstract class — because an abstract class can implement functionality in a method. All of the reusable code for retrieving data from a database table is kept in Data_Access.

Now, finally, let’s see all of this in action.

The Index Page

I’ve created a file called index.php which is our landing page for this project. It’s shown below, in Image 5.

Image for post
Image for post
Image-5: Index Page

There’s no rocket science here. The Index page instantiates the Customers class, executes the getList function, passing the variable which indicates a list of all customers is desired. This returns an array of customers and displays the list to the screen in a table.

We embed each customer number in a link to the customerOrders.php page, which we’ll create next, that displays all the orders for the selected customer.

The result looks something like this:

Image for post
Image for post
Image-6: The Customer List

That’s it! Congratulations if you see a list similar to the one in the image above.

Now we’ve create a small web application that uses an abstract class and implements an interface. To illustrate the potential of this, let’s go to the next step in the use case and create a page that displays customer orders.

The Orders Class

Now let’s create our next concrete database class: orders.php.

Image for post
Image for post
Image-7: Orders

The Orders class is nearly identical to the Customers class. It begins with a constructor that attempts a database connection by calling dbConnect.

It has to follow the same rules as Customers because it also implements the Data_Interface interface class. Therefore it too is required to have an insertRecord, deleteRecord, and getList function.

Here’s one of the benefits of interfaces: Now we have multiple classes that must follow the same rules and include all of the same specified methods and the required parameters. If I’m working with any class that is a member of Data_Interface, I can always know it will be required to have these methods.

Like Customers, the getList function in Orders requires a parameter variable intended to be used as a filter in the SELECT statement. In this case, I’ll take advantage of that because we only want to display the orders for the selected customer.

Once the query string is created, Orders can call the getResultSetArray function, just like Customers.

And now we see the benefit to abstract classes. In this case, both Customers and Orders extend Data_Access and share all the common code within that abstract class. The code in Data_Access is not specific to any single database table, but instead applies to all database tables and is by its very nature… abstract.

Let’s wrap this up with our last page, which will display the customer orders.

The Customer Orders Page

In Image 8 below we see the code for the Customer Orders page.

Image for post
Image for post
Image-8: Customer Orders Page

As before, there’s not a lot of rocket science here. This page instantiates the Orders class and executes the getList function, passing the customer number that was sent over in the URL as a GET variable. The resulting list is displayed in an HTML table as before.

The result looks something like this:

Image for post
Image for post
Image-9: The Customer Orders List

There you have it! We’ve completed our entire use-case. We’ve built a real-life web application that incorporates abstract classes and interface implementations.

Additional Things You Should Know About Interfaces

Interfaces are really pretty cool and there’s more that you can do with them besides enforcing methods in your concrete classes.

First, you can implement multiple interfaces at once. Suppose in our example we have an interface called Accounts_Receivable that has functions specific to Customers (e.g. creditCheck) that don’t apply to Orders.

<?php

interface Accounts_Receivable {
public function creditCheck($varCustomerNumber);
}

If we wanted to implement this interface in Customers along with Data_Interface, it would look like this:

require_once ('data_access.php');
require_once ('data_interface.php');
require_once ('accounts_receivable.php');
class Customers extends Data_Access implements Data_Interface, Accounts_Receivable {

You would merely separate the interface names with commas. In this example, Customers would now be required to implement the creditCheck function along with its required parameter.

One other thing you can do with interfaces is use instanceof to determine if concrete classes implement selected interfaces. For example, perhaps we wanted to determine whether a class implemented the Data_Interface interface. We could do the following:

<?php

$cCustomers = new Customers;

if ($cCustomers instanceof Data_Interface) {
echo 'You are a database class!';
}

This gives you the ability to treat your classes differently, depending on the types of interfaces they implement.

Additional Things You Should Know About Abstract Classes

The biggest difference between abstract classes and interfaces is that abstract classes can implement code that is shared by the classes that extend them.

However, abstract classes can also have abstract methods. These methods are very much like interfaces, as they are represented only by a function signature (no body) and are required by the concrete classes that extend the abstract class.

The abstract class Data_Access in our example didn’t utilize any abstract methods. Therefore, the classes that extended Data_Access were not required to implement those methods.

However, we could have just as easily included some of our interface functions in our abstract class as abstract methods, and they would still be required in the extending classes.

Data_Access could have included the following lines:

<?phpabstract class Data_Access {abstract function insertRecord();
abstract function deleteRecord($varRecordId);

Then the two functions could be removed from the interface class and we would still have the same results. Now the abstract class would enforce that insertRecord and deleteRecord must exist in Customers and Orders.

Summary

Interfaces are a blueprint or contract that ensures the concrete classes that implement them include all of the methods required by the interface. You can also query your concrete classes to determine if they implement certain interfaces and then work with different types of classes in different ways. A concrete class can implement one-to-many interfaces.

Abstract classes can also use abstract methods to offer a type of blueprint or contract that ensures concrete classes that extend them to implement required methods. However, abstract classes can go a step further by providing classes that implement code that concrete classes can inherit to achieve common functionality. A concrete class can only extend one abstract class at a time.

That should get you started. There’s still more you can learn about the power of abstract classes and interfaces, but the lessons here are the basics to help you organize your code in the right ways.

Better Programming

Advice for programmers.

By Better Programming

A weekly newsletter sent every Friday with the best articles we published that week. Code tutorials, advice, career opportunities, and more! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Casey McMullen

Written by

Startup Entrepreneur. Internet Software Developer. Classic Rock Guitar Player. Harley-Davidson owner.

Better Programming

Advice for programmers.

Casey McMullen

Written by

Startup Entrepreneur. Internet Software Developer. Classic Rock Guitar Player. Harley-Davidson owner.

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store