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.
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.
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
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.
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.
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).
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.
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.
Rubbish! Interfaces were created to solve a problem in statically typed languages which made it impossible to achieve polymorphism without inheritance, as explained in Polymorphism and Inheritance are Independent of Each Other. PHP is dynamically typed and does not have this problem, therefore this "solution" is totally redundant and irrelevant and as such it violates the YAGNI principle. More details can be found in A minimalist approach to Object Oriented Programming with PHP - Interfaces.
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.
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.
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. If you change or add a method signature in an interface then you must make a corresponding change in all classes which implement that interface.
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.
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 which states the following:
Implementation dependencies can cause problems when you're trying to reuse a subclass. Should any aspect of the inherited implementation not be appropriate for new problem domains the parent class must be rewritten or replaced by something more appropriate. This dependency limits flexibility and ultimately reusability. One cure for this is to inherit only from abstract classes, since they usually provide little or no implementation.
That last statement
since they usually provide little or no implementation is contradicted later on in the book when it describes the Template Method Pattern which uses a mixture of invariant methods (with implementations) and variable methods (without implementations) in an abstract class. That chapter specifically states that
Template methods are a fundamental technique for code reuse, which means that the more template methods you have the more implementations you have.
In Object Composition vs. Inheritance I found the following statements:
Most designers overuse inheritance, resulting in large inheritance hierarchies that can become hard to deal with. Object composition is a different method of reusing functionality. Objects are composed to achieve more complex functionality. The disadvantage of object composition is that the behavior of the system may be harder to understand just by looking at the source code. A system using object composition may be very dynamic in nature so it may require running the system to get a deeper understanding of how the different objects cooperate.
However, inheritance is still necessary. You cannot always get all the necessary functionality by assembling existing components.
The disadvantage of class inheritance is that the subclass becomes dependent on the parent class implementation. This makes it harder to reuse the subclass, especially if part of the inherited implementation is no longer desirable. ... One way around this problem is to only inherit from abstract classes.
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.
When you consider that the definition of encapsulation is
The act of placing ALL the data and ALL the operations that perform on that data in the same class then the only real way to violate encapsulation is to NOT put all of those two things in the same class. The practice of Command Query Responsibility Segregation (CQRS), which separates the methods which retrieve from those which modify, is an example of this violation.
The following newsgroup post was made by a person with the moniker cpradio:
TomBMe. It doesn't serve a single responsibility, it serves multiple, which is by definition is a god object. I also object to him classifying it as an "abstract class". I write abstract classes daily, that is not an abstract class. It is a base class that gets inherited by all other classes to provide various low level operations - it isn't defining what implementations are permitted, it is defining the actual implementation and you'd have to override anything you don't want (or want to work differently).
sigh Ok let's take this one to vote. Who thinks tony's 9000 line class is a god class?
What multiple responsibilities? According to the Single Responsibility Principle a "responsibility" is either presentation logic, business logic or database logic which is a word-for-word description of the 3-Tier Architecture which I have implemented in my framework. That abstract class is only ever inherited by objects in the business/domain layer therefore it contains logic for only one of those 3 tiers and conforms to Robert C. Martin's definition of SRP.
You say that
it is not an abstract class as it gets inherited by all other classes to provide low level operations, but that argument is completely bogus. There is no limit to the number of subclasses which a superclass, whether abstract or concrete, can have. The fact that my abstract class is inherited hundreds of times simply means that it is very reusable. There is no limit to the types of method - either low level or high level - which a superclass may contain.
You say that
it isn't defining what implementations are permitted, it is defining the actual implementation, but that argument is completely bogus. Unlike an interface where the methods are physically restricted from containing implementations, within an abstract class there is no such restriction.
You say that
you'd have to override anything you don't want (or want to work differently), but you obviously have failed to spot that this abstract class is filled with instances of the Template Method Pattern which is a mixture of invariant/fixed methods and customisable/variable methods. The invariant methods provide standard processing which should never be changed while the variant methods have empty implementations which can be overridden in any subclass. Each concrete table class should therefore contain nothing but these "hook" methods.
His post also included the following:
Abstract Class definition:
- An abstract class cannot be instantiated.
- An abstract class may contain abstract methods and accessors.
- It is not possible to modify an abstract class with the sealed (C# Reference) modifier because the two modifiers have opposite meanings. The sealed modifier prevents a class from being inherited and the abstract modifier requires a class to be inherited.
- A non-abstract class derived from an abstract class must include actual implementations of all inherited abstract methods and accessors.
Here are my responses to each of the above points:
This is a typical example of a criticism of my work where the critic does not understand what he is talking about, so rather that pointing out an error in my understanding he is actually pointing out an error in his understanding. This is why I ignore such criticisms and take great delight in pointing out their ignorance.
As described in Interfaces are required in OO languages interfaces are a relic of a bygone era and are no longer required in modern dynamically typed OO languages. Yet strangely they still persist, mainly because new programmers are still being taught that they are relevant because of principles such as Program to the interface, not the implementation and the Interface Segregation Principle. If I don't use interfaces then how can I follow these principles?
When I started to write OO code using PHP I did not use interfaces simply because they did not exist in PHP until much later. When they were introduced, for no good reason other than other OO languages had them, I could not see any point in using them. My code worked without interfaces, therefore interfaces were not necessary. Besides, I had all the functionality and reusability that I needed by inheriting from an abstract class.
Eric Gamma, one of the authors of the GoF book had the following to say in Design Principles from Design Patterns:
This approach [using interfaces] gives you flexibility, but it also separates the really valuable part, the design, from the implementation, which allows clients to be decoupled from the implementation. One question is whether you should always use interfaces for that. An abstract class is good as well. In fact, an abstract class gives you more flexibility when it comes to evolution. You can add new behavior without breaking clients.
When you add a new method to an interface, you break all your clients. When you have an abstract class, you can add a new method and provide a default implementation in it. All the clients will continue to work. As always there is a trade-off, an interface gives you freedom with regard to the base class, an abstract class gives you the freedom to add new methods later. It isn't always possible to define an interface in an abstract class [see note below], but in the light of evolution you should consider whether an abstract class is sufficient.
Note: The statement
It isn't always possible to define an interface in an abstract class is out of date because in PHP an abstract class is allowed to contain both abstract and non-abstract methods, and an abstract method has exactly the same characteristics as an interface.
One very important reason why abstract classes are superior to interfaces is that they give you the opportunity to implement the Template Method Pattern. It is strange that Erich Gamma did not mention this in his interview as it is one of the 23 patterns contained of the GoF book, which says:
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour.
The RADICORE framework makes extensive use of this pattern, as described in The Template Method Pattern as a Framework.
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, and I never create deep inheritance hierarchies. 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.
|16 Apr 2022
|Added What is better - an interface or an abstract class?.
|01 Feb 2022
|Added Wrong definition of an Abstract Class.
|28 Sep 2017
|Added Myths about Interfaces and Summary.