Interfaces or Abstract Classes?

« »

Developers in PHP have a wide array of useful tools for object oriented development. From a full visibility model to concepts like abstract classes and interfaces, the PHP developer can make use of each tool in its own way and offer up an array of interesting solutions.

The problem is that often this leads to confusion among developers as to which tool to use. This isn’t uncommon in PHP; in fact, it’s very common that developers use the wrong tool or the right tool in the wrong way.

Today, let’s examine the use of abstract classes versus interfaces for object development and design.

The benefit of the abstract class

An abstract class is a class that cannot be instantiated directly; it must instead be extended by a child, and have all abstract methods defined. An abstract class may also describe concrete methods which are available to the child class, but is not required to describe any concrete methods.

For example, an abstract class might be defined as such:

<?php

abstract class MyAbstractClass {
    
    abstract public function testFunction($argA, $argB);

}

?>

In this example, both the class and the abstract function are marked as such; the abstract function has a defined signature but instead of opening and closing brackets, the function definition simply ends with a semicolon. This is very similar to how an interface might be defined; the difference is that in abstract classes, developers can actually define concrete methods (which I did not do). Developers can also define protected abstract members as well, while all interfaces must contain only public methods.

If you attempted to instantiate this class without first extending it, you would receive a fatal error. Likewise, if you extended it without either marking the child as abstract or implementing all abstract methods, PHP would give you a fatal error.

The advantage of interfaces

Abstract classes might at first look seem like a good replacement for interfaces: first, you can define protected methods and concrete methods. Second you can simply inherit from the abstract class as a base class. However, things aren’t that simple.

PHP allows for only single inheritance, meaning that a child can only have one parent. In contrast, a class can implement multiple interfaces. In that way, having a CountableInterface and an IterableInterface allows you to implement both of these interfaces on an object, or implement only one of them (and more importantly, appropriately typehint). This makes it easier to compose your objects.

Using an interface allows developers to design by contract, a principle that makes extension easier. Developers may face some code implementation challenges, especially with duplicated code (which I would argue indicates a good case for inheritance), but more often than not an interface provides distinct advantages for developers.

Which do you choose?

Developers ultimately get to choose their tools of the trade. They should choose wisely to avoid having to rewrite their code later on when they discover that their needs have outgrown their design. In this way, I favor interfaces unless I absolutely need an abstract class (which I would use when designing a generic database component). Still, the use for abstract classes is smaller than it appears at first, and I recommend using interfaces unless you can’t avoid using an abstract class.

Brandon Savage is the author of Mastering Object Oriented PHP and Practical Design Patterns in PHP

Posted on 2/21/2013 at 7:00 am
Categories: PHP, Best Practices, Object-Oriented Development

Evert (@evertp) wrote at 2/21/2013 8:08 am:

I’d argue that traits + interfaces is a form of multiple inheritance.

Paul (@Seiffertp) wrote at 2/21/2013 8:57 am:

I think that you can’t really compare interfaces with abstract classes since they have completely different meanings. An abstract class describes an abstract super-type – an interface only a set of methods that client objects might want to use. People should start using inheritance for sub-typing instead of for making functionality of other classes available in an object. This is what traits and composition are for…

Milan Popović (@komita1981) wrote at 2/21/2013 9:42 am:

Why don’t you want to define concrete methods in abstract classes?

Anthony (@ircmaxell) wrote at 2/21/2013 9:59 am:

Evert,

Traits are not multiple inheritance. And neither are interfaces.

Inheritance requires the ability to overload methods. Traits do not provide that ability. Additionally, inheritance is also about typing, something that traits by very definition do not provide. Inheritance provides sub-type polymorphism. Traits have no mechanisms for that. Traits are nothing more (literally) than compiler-aided copy/paste. Inheritance is much more than just copy/paste.

Interfaces only provide a contract, they do not define a “type”. Therefore, interfaces do not provide sub-type polymorphism. They are very useful for providing polymorphic behavior, but they are a very different concept than inheritance.

It’s a very subtle difference mind you. In practice you can use traits and interfaces to simulate multiple inheritance. But it’s not multiple inheritance. And I think it’s very important to draw that distinction so that we communicate clearly. Traits have a very specific contract with the developer. They are not intended to provide polymorphism or typing. They are intended for static (compile-time) horizontal code re-use only.

My $0.02 at least…

Evert (@evertp) wrote at 2/21/2013 10:47 am:

I disagree that interfaces don’t provide ‘type’. I use that concept everywhere, and generally only force type based on interface. If I combine that with traits I can effectively achieve what multiple inheritance also provides. But I agree that it’s not _exactly_ the same thing on a language-level.

As with all of these abstract concepts it’s subjective though. To me, with the design problems I am facing, I can achieve a form of multiple inheritence, which is kinda where I’m coming from.

Wayne wrote at 2/21/2013 1:57 pm:

This is a pretty good writeup. I did a comparison of Interfaces an Abstract Classes about a year ago. http://waynemay.com/interfaces-vs-abstract-classes-in-php/

Paul (@Seiffertp) wrote at 2/22/2013 5:23 am:

@Evert, I get your point. Yes, interfaces can define types, but from the client’s point of view. I like to see it like this: objects have a type that is purely defined by their class and their superclasses. If they fulfill some contract used by other objects, they can express this by implementing an interface. However, this does not change the object’s type, but states that the object _also_ acts as an implementation of the contract declared by that interface. Does that make sense to you?

Cheers,
Paul

Evert (@evertp) wrote at 2/22/2013 5:42 pm:

It could make sense, but you’ll find OOP and design pattern-purist mostly typing on interfaces at all time, because they are more flexible, and other reasons.

I’m not a purist though, I am a pragmatist and I try to use the best tool for the job..

I find in the project I work on (a relatively large and complex open source library, been at it for 6 years now) that slowly the places where I made a decision earlier to use (abstract-)classes as the base type, I’m shifting towards interfaces.

So generally I disagree, in most cases where I need to spend the most time on quality, durability and backwards compatibility (public, open source code basically), type is in 90% of the cases provided by some interface, and implementation by classes.

I feel very different about private code though, and maintain very different design goals for code where both the API and the consumer is controlled, for example within the same company. In those cases I try to work as ‘flat’ as possible, use inheritance sparingly and interfaces almost never. For private code I my primary goal is to write code that extremely easy to refactor, throw away or rewrite.

Stephen S. Musoke (@ssmusoke) wrote at 2/25/2013 9:04 am:

Interfaces are a contract for behavior – any class that implements an interface must provide an implementation for the methods in the interface.

Abstract classes – form a basic building block with common behavior for a hierarchy of classes and can force child classes to enforce certain behavior

Interfaces are great for grouping related behavior and can be used across a complete codebase while Abstract classes are only good for behavior in a specific hierarchy of objects.

A good mix would be to define interfaces and have base Abstract classes for specific hierarchies

Jon wrote at 4/3/2013 5:02 pm:

Java 1.8 , as part of the Lambda package, is going to allow what is called “Defender methods” capability, which allows you to have a default implmentation of a method completely defined in a interface definition, thereby enabling the inheritance of multiple interfaces without the requirement of having to define what those methods do unless you want to re-define them (different than a override).

« »

Copyright © 2023 by Brandon Savage. All rights reserved.