Tony Marston's Blog About software development, PHP and OOP

The difference between an interface and an abstract class

Posted on 16th September 2017 by Tony Marston

Amended on 18th September 2017

Introduction
Abstract method
Static method
Plain method
Interface
Abstract class
Concrete (plain) class
Myths about Interfaces
Summary
Amendment history
Comments

Introduction

This is an attempt to explain the differences between an interface, an abstract class and a non-abstract class in the PHP language. Other languages may have slightly different implementations.

Each of these constructs may contain only certain types of method, so it is necessary to explain what these are first.

Abstract method

An abstract method is defined as a method signature without any method body - i.e. it has no implementation.

When defined within an abstract class it requires to be prefixed with the keyword abstract. This is not necessary when defined within an interface as all methods within an interface are abstract by default.

When something containing an abstract method is incorporated into a non-abstract class, either by using the implements or extends keyword, that abstract method must be defined in that class with the same signature, at which point the method body can also be defined.

Static method

A static method can be accessed without having to first instantiate its class into an object. It is accessed using the expression <classname>::<method> such a singleton::getInstance().

A static method cannot use the pseudo-variable $this.

Plain (non-abstract) method

A plain method has a signature and a body, but the body may be empty. This is different from an abstract method which can have a signature but no body.

If a plain method is inherited it can be used in the subclass without having to be defined in the subclass.

A plain method can use any of the visibility modifiers public, private or protected.

Interface

An interface defines one or more abstract methods. It cannot contain any plain or static methods.

An interface is identified by having the keyword interface in front of the interface/class name

An interface can contain constants, but not any variables.

An interface cannot be instantiated into an object.

No methods in an interface can have visibility modifiers as every method is public by default.

An interface can be inherited by another interface using the implements keyword.

An interface can be inherited by a class, either abstract or non-abstract, using the implements keyword.

Abstract class

The following description of an abstract class is taken from Components, Frameworks, Patterns (PDF) by Ralph E. Johnson:

An abstract class is a class with no instances, so it is used only as a superclass. An abstract class usually has at least one unimplemented operation deferred to its subclasses. Since an abstract class has no instances, it is used as a template for creating subclasses rather than a template for creating objects. Frameworks use them as designs of their components.

An interface can contain any mixture of abstract methods, plain and static methods.

An abstract class is identified by having the keyword abstract in front of the class name

An abstract class cannot be instantiated into an object.

It can inherit one or more interfaces using the implements keyword.

It can inherit no more than one abstract class using the extends keyword.

An abstract class cannot inherit from a non-abstract class.

Any abstract methods which are inherited, either from an interface or another abstract class, do not need to be defined as signatures and their implementations are only required when inherited by a non-abstract class.

It can contain any number of constants, variables and methods (either abstract or otherwise).

Concrete (plain) class

This can contain any number of static or plain methods.

It cannot contain any abstract methods otherwise it would have to be an abstract class.

It can contain any number of constants and variables.

It can be instantiated into an object.

It can extend no more than one class, abstract or non-abstract.

It can implement any number of interfaces.

It can be inherited by another class, but not an abstract class.

A class which is inherited is known as the superclass or parent class, while the class which does the inheriting is known as the subclass or child class.

If any abstract methods are inherited then these must be defined with exactly the same signature and with whatever implementation is desired.

If any plain methods are inherited then these need not be defined, but if they are they must have the same signature and with whatever implementation is desired.

If a method in the superclass is overridden in the subclass then the implementation in the subclass will be executed at runtime, not the implementation in the superclass.

Constants, variables and methods which are not inherited can be given any visibility modifiers.

An abstract method inherited from an interface must be defined with the same visibility (public).

An abstract method inherited from an abstract class can be defined with the same or less restrictive visibility.

Myths about Interfaces

My first OO-capable language was PHP 4 which did not support interfaces, only encapsulation, inheritance and polymorphism, and I have been able to produce reliable and cost-effective software using nothing but these three. However, since I have been publishing articles on my approach I have been constantly bombarded with accusations saying that I am not a "proper" OO programmer because I am not using interfaces. I choose to ignore these accusations because they are based on a bunch of myths and are completely without merit.

Interfaces are required in OO languages.
Rubbish. Interfaces were invented to solve a problem which existed decades ago when processing speed was just a fraction of what it is now, and a mechanism was needed to check that a method with that signature existed in an object before it was called. This could not be done at run-time, so it was done at compile time. Please refer to Polymorphism and Inheritance are Independent of Each Other for details. This problem no longer exists in modern languages with modern high-speed processors, so if the problem no longer exists why is there still a need for a solution?
Interfaces provide an alternative type of inheritance
I often read about two flavours of inheritance:

This to me is a total abuse of the term "inheritance" as nothing is actually inherited with interfaces. If you look up the definition of inheritance you will see that it entails something of substance being given to someone without any effort on their part. If a relative dies and leaves you a fortune in their will then you suddenly find yourself in possession of this fortune for no good reason other than being named as the beneficiary.

In OO programming inheritance works slightly differently as instead of the current owner of this "thing of substance" (the superclass) naming you as their beneficiary, any number of subclasses can choose to inherit (using the keyword extends) from the same superclass. This means that the entire contents of the superclass is then shared by any number of subclasses without any of these subclasses being known to the superclass.

There is no such thing as interface inheritance as nothing is actually passed down to the beneficiary. Not only is there no implementation (you have to code it yourself), you don't even "inherit" the method signature as you have construct your own duplicate. It's like saying to someone "Congratulations, you have just inherited a briefcase full of money" and when they ask "OK, so where is it?" you tell them that they have got to provide both the money and the briefcase themselves. So if nothing is actually given to you because you have had to provide it yourself, what exactly is it that you have inherited? There is nothing of substance, only a concept.

Interfaces provide a better programming style
In this Wikipedia article it says the following:
The use of interfaces allows for a programming style called programming to the interface. The idea behind this approach is to base programming logic on the interfaces of the objects used, rather than on internal implementation details. Programming to the interface reduces dependency on implementation specifics and makes code more reusable.

This to me is a load of bollocks balderdash. Firstly, when you call a method in an object you have no knowledge of how that method is implemented in that object, just that a method with that signature exists. This allows you to call the same method on a different object which then has a different implementation. This is what polymorphism is all about, and you must have polymorphism before you can use Dependency Injection (DI). Secondly, the idea of code reuse involves more than duplicated method signatures, it involves a block of code (the implementation of an idea) being defined just once and then being called from multiple places instead of that code being duplicated in multiple places. This is what the DRY principle is all about.

In the article Interface inheritance vs Implementation inheritance the author states the following:

The concept of preferring interface inheritance probably came first from the C++ and COM programming days, where an abstract class would be used to define methods in a base class and the inheriting classes would be required to implement the methods.

This is rubbish as the subclass is only required to provide implementations for abstract methods, and an abstract class need not contain any abstract methods, only concrete ones. Concrete methods in an abstract class are automatically inherited by a subclass, and need only be defined in the subclass should the implementation be changed.

Interface inheritance avoids coupling
In the same article he then asks the question "So why prefer interface inheritance to implementation inheritance?" to which the answer is:
The simple answer to this is to avoid coupling between two components of an application.

The idea that you can avoid coupling when one module calls another tells me that this person does not understand what coupling actually means. When you have an application comprised of many modules which must interact between themselves then you automatically have coupling and dependencies. This is unavoidable in a modular application. Take the following examples:

If ModuleA calls ModuleB then the following statements apply:

A dependency between two modules/objects is a binary condition - if one calls the other then there is a dependency. If neither calls the other then there is no dependency.

Similarly if one module calls the other then there is coupling. If neither calls the other then there is no coupling. However, the strength of the coupling has ramifications where loose coupling is considered to be good while tight coupling is considered to be bad. Tight coupling manifests itself when a change in ModuleB causes a ripple effect of corresponding changes in other modules. If you change a method signature in a module then you automatically have to change all those other modules which reference that signature.

It is not possible to eliminate coupling entirely as a completely decoupled application will not work. Two modules which are tightly coupled have less chance of being reused, so the only way to guarantee more code reuse is to have coupling which is as loose as possible. For example, if I have a controller C1 which is tightly coupled to a model M1 then I cannot use that controller with any other model, and I cannot use that model with any other controller. In my RADICORE framework I have moved to the other end of the spectrum by allowing any of my 50+ reusable controllers to be used with any of my model classes (of which there are currently 400+). So by minimising (which is NOT the same as eliminating) the level of coupling I have maximised the level of code reusability.

The idea that Dependency Injection (DI) de-couples the interconnected modules is a complete fallacy. You cannot use DI unless you have polymorphism, and you cannot have polymorphism unless multiple objects share the same method signature(s), which is usually achieved by those objects inheriting from the same abstract class. Take the following example:

ModuleA calls ModuleB(n) where 'n' identifies a particular module which shares that signature. Using DI ModuleA does not contain the code to work out which version of ModuleB it needs to instantiate, that is done outside of ModuleA and then injected into it. ModuleA then calls the method on whatever version of ModuleB that was injected into it.

You should be able to see here that there is still both a dependency and coupling between ModuleA and all the versions of ModuleB as one is calling a method using the signature defined in the other, all that has happened is where a particular version of ModuleB is identified and instantiated.

Inheritance breaks encapsulation
This is an extension of the idea above concerning coupling. When I first heard it I honestly thought it was a joke as inheritance and encapsulation, along with polymorphism, are supposed to be the main criteria for what makes a programming language Object Oriented in the first place, so to say that two of these three violate each other strikes me as being is a load of bollocks balderdash. Yet there are some comedians out there who preach this idea as being the gospel truth. Take a look at the following if you don't believe me:

If you read through those articles you will see where one says the following:

If a derived class is allowed to access members inherited from a base class, changes in the base class may require maintenance of the derived class as well.

Note the use of the words if and may. This shows that problems are only possible under certain circumstances, not guaranteed under all circumstances. The response to that should be obvious - be careful when you make changes and you won't have any problems.

Others say something like the following:

It breaks encapsulation since it exposes a subclass to implementation details of its superclass.
Encapsulation is about information hiding, and when you inherit from a superclass the information inside that superclass is no longer hidden in the subclass.

These people fail to understand that when you inherit the contents of class C1 into class C2, then the resulting object combines the contents of C1 with the contents of C2. Anything in C1 which should be hidden from C2 should have its visibility set correctly. Any problem is therefore with the programmer's implementation of the concept, not the concept itself.

There is another point which is lost on most people - the "problem" can only materialise when you inherit from one concrete class to make a completely different concrete class. The "solution" is therefore obvious - only create a concrete class by inheriting from an abstract class, as was documented as long ago as 1994 in the book Design Patterns: Elements of Reusable Object-Oriented Software.

To me it is a question of balance. You have to weigh the advantages of inheritance against the disadvantages. The advantages of having large amounts of code which is reused in multiple places, thus avoiding the need for code duplication, is guaranteed at all times. The disadvantages of having large amounts of shared code is that if you make any changes to the base class you may have to make corresponding changes in all derived classes, but that is only a possibility when you change the base class. In other words, the advantages are guaranteed whereas the disadvantages are only possibilities. I'm afraid that, IMHO, the advantages outweigh the disadvantages by a huge margin, so I will continue to use inheritance as it was designed to be used.

Summary

I hate interfaces, and I do not use them. Refer to A minimalist approach to Object Oriented Programming with PHP for a detailed explanation.

I love abstract classes as they enable the use of the Template Method Pattern.

There are some people out there who believe that an abstract class can only contain abstract methods, but they fail to understand that this would make it no different from an interface. An abstract class provides reusable implementations whereas an interface does not.

In my RADICORE framework, which deals with database applications, every Model component in the Business layer represents a single database table, and all the code which is common to database tables has been defined once in a single abstract table class which is then inherited by every one of my 400+ concrete table classes. This abstract class is filled with 200+ concrete methods, not abstract methods, so none of them need be defined and implemented in the subclass. This provides a huge amount of reusable/sharable code, and as this is supposed to be the objective of OOP I absolutely refuse to acknowledge any criticisms which say that my implementation of OOP is wrong.

I never inherit from one concrete class in order to create a different concrete class. I only ever extend a concrete class when a different user transaction requires a different implementation in one or more of the custom hook methods.

Amendment History

28 Sep 2017 Added Myths about Interfaces and Summary.

counter