Skip to content
Home » Use the Adapter Pattern in PHP | Learn Design Patterns in 2023

Use the Adapter Pattern in PHP | Learn Design Patterns in 2023

What is the Adapter Pattern in PHP

The adapter pattern in PHP introduces a class that acts as an intermediary between two different classes that cannot collaborate directly. This intermediary class is what we call an Adapter. The article has an application that uses JSON but doesn’t comply with the XML parser. The image of the complete solution shows an Adapter sitting between the two parsers.

Adapter Pattern in PHP
Adapter Pattern in PHP

That may not make sense at the moment, but you will know how the Adapter class makes these two classes go hand in hand, which was otherwise impossible because the Client cannot use the XML parser. Stay tuned to discover more.

Definition | Adapter Design Pattern in PHP

“The adapter design pattern is a structural design pattern that converts the interface of a class into another interface to make them compatible.”

Adapter Pattern
Adapter Pattern

The object of this pattern is to make two incompatible classes compatible by using an Adapter in between. Let’s learn this pattern from a real-world example.

SchemaVisualizer | A Real-World Example Using the Adapter Design Pattern

A development team is working on SchemaVisualizer. SchemaVisualizer takes a JSON schema and builds a block model, as shown in the image.

Adapter Pattern in PHP
Employee Schema

A developer has been assigned to integrate the JSON parser with the application. He builds the feature, which has been designed as follows.

Client uses JSON Parser
Client uses JSON Parser

The feature integrates with the main application, but the design could’ve been better. Can you think of a better design?

Program to Interface, not Implementation

The design lacks abstraction because the Client has been exposed to the concrete JSONParser class. There could’ve been a Parser interface, and the Client class would have used that instead of the concrete class. 

Adapter Pattern in PHP
Parser Interface

But what’s the benefit?

Programming to an interface makes your application more flexible. Polymorphism is a fundamental concept of object-oriented programming, and it helps us abstract the concrete classes by programming to their interfaces or parent classes. 

Consider what happens when the developer adds a new parser if the client code has been coupled to the JSON parser.  How does the developer ensure it works equally well with an XML parser, for instance? 

That’s why an interface is helpful because, in that case, the developer would just implement it with the XML parser. The Client won’t really bother about what concrete class has been initialized as long as it implements the same interface. 

To change or not to change?

So now the developer has learned about wise design decisions and has vowed to refactor the application that way, but it would take a week to do so, and there is an urgent feature now.

Guess what? There is a request to add XMLParser class to the application, and that too by the end of the day. What now? The developer needs to think of a quick fix because there is no time to refactor. He can do refactoring later, though.

Incompatible Interfaces

Let’s zoom in on the problem now. We have an existing JSONParser and now a new XMLParser. They are two classes with different types and no common interface to use them polymorphically. The Client expects a JSONParser and nothing else.

In other terms, the Client is incompatible with XMLParser

So, the developer is left with no other option than modifying the existing Client, bloating it with IF/ELSE, and type checks.

Refactored Client Code
Refactored Client Code

So, what’s wrong with this implementation?

Single Responsibility Principle

The single responsibility principle states, “A class should have one and only one responsibility.” The current implementation violates it by bloating the Client and adding more responsibilities. 

Open-closed Principle

The open-closed principle states, “A class should be closed to modification but open for extension.” So, the current implementation has modified the Client solely because the design is not flexible. An interface would have prevented that, but you have had concrete classes in your Client class.

Inflexible Design

This idea is somewhat linked to the last two because these principles are based on flexible and maintainable designs. Program to an interface and not implementation is another polymorphism mantra that helps us design extendable and flexible software designs.

So, How to go about this Problem?

The developer needs more time for refactoring, and to get through the incompatibility problem between the Client and XMLParser, he needs to come up with something more flexible than IF/ELSE and type checks. 

A little research leads him to the adapter design pattern. 

But What is an Adapter?

An adapter makes something look like a different thing. Sounds too abstract? Let’s define it in more object-oriented OO lingo.

An adapter takes in an interface and converts it to the one that the client class expects. Suppose the client class expects interface A, and you have a library that exposes interface B.  We need an adapter that will adapt B to A without having the client worry about these adaptations going underneath. 

Still confused? Let’s see a real-world analogy to make it more clear.

A real-world analogy

Suppose you travel from the US to the UK. You want to charge your laptop, but that’s what you’re faced with.

Adapter Pattern in PHP
Incompatible Interfaces

What’s the way out? How to make this socket and plug compatible? The answer is Adapter.

Adapter makes both compatible
The adapter makes both compatible

The adapter sits between the socket and plus and provides a way to make them both compatible. In other words, the adapter changes the interface to what the plug expects. That’s the adapter’s job: to change an interface to the one that a client expects.

This idea of an adapter is pretty much the same in OO designs. You take an interface and adapt it to what the client class expects. 

Target, Adapter & Adaptee

The adapter design pattern has three building blocks.

  1. Target    – The class or interface to be adapted to. The JSONParser in this case.
  2. Adapter – The class that acts sits in between and makes adaptations.
  3. Adaptee -.The class or interface has to be adapted. The XMLParser in this case. 

The following is a generic class diagram of the adapter design pattern.

Adapter Pattern in PHP
Adapter Pattern

Object Adapter vs Class Adapter

The object adapter uses composition over inheritance. It sits in between the adapter and the adaptee. When it gets a method call, it delegates it to the adaptee by calling methods on the adaptee object.

Object Adapter
Object Adapter

The class adapter uses the same three components, Target, Adapter, and Adaptee, but it prefers inheritance over composition. Moreover, it uses multiple inheritances, which is impossible in many programming languages. PHP, too, doesn’t have multiple inheritance, but it can still use Traits.

Class Adapter
Class Adapter

Which one is better?

Well, there is no clear-cut answer to it except that object adapters are more common because multiple inheritance is not supported across many programming languages. Besides, object adapters are flexible in working well with any adaptee subclass. Class adapters stick to one class but can override its method and don’t need an adaptee object to delegate calls to.

We’ll focus on the object adapter and design the solution using it.

Complete Architecture | Adapter Design Pattern in PHP

Adapter Pattern in PHP
Adapter Pattern in PHP

Adapter Design Pattern in PHP

The following is the complete solution using the adapter pattern in PHP.

Code | Adapter Design Pattern in PHP

<?php
 
//Target
class JSONParser {
 
    function parseJSON() {
        echo "Parsing JSON".PHP_EOL;
    }
}
 
//Adapter
class XMLtoJSONAdapter extends JSONParser {
    private $adaptee;
 
    function __construct($adaptee) {
        $this->adaptee = $adaptee;
    }
 
    function convertXMLtoJSON() {
        echo "Converting XML to JSON".PHP_EOL;
    }
 
    function parseJSON() {
        $this->adaptee->parseXML();
        $this->convertXMLtoJSON();
    }  
}
 
//Adaptee
class XMLParserv1 {
   
    function parseXML() {
        echo "Parsing XML".PHP_EOL;
    }
}
 
class Client {
    private $parser;
 
    function __construct($parser) {
        $this->parser = $parser;
    }
 
    function setParser($parser) {
        $this->parser = $parser;
    }
 
    function useParser() {
        $this->parser->parseJSON();
    }
}
 
function main() {
    $jsonParser = new JSONParser();
    $xmlParser  = new XMLParserv1();
    $xmltoJSONAdapter = new XMLtoJSONAdapter($xmlParser);
 
    $client = new Client($jsonParser);
    $client->useParser();
    $client->setParser($xmltoJSONAdapter); //Adapter delegates call to the XML parser.
    $client->useParser();
}  
 
main();
?>

Output | Adapter Design Pattern in PHP

Parsing JSON
Parsing XML
Converting XML to JSON

Pros and Cons of the Adapter Pattern in PHP

ProsCons
Single responsibility principle: You can use adapters to separate data conversions from the business logic in Adapter and Adaptee classes. Adds complexity to the code by adding a new set of classes and interfaces.
Open/closed principle: You can use Adaptee sub-classes polymorphically in the Adapter class. You can also add more adapters as long as they extend or implement the same target the Client has been using.Sometimes an overkill if a minor readjustment to the code can make two interfaces compatible with each other.

Where is the Adapter Pattern Used?

  • When you want to add a set of classes with an interface that isn’t compatible with the rest of your code.
  • When you want to add common functionalities to some existing sub-classes with a common interface. The adapter can extend that interface and then wrap the sub-class, adding the functionality dynamically.
  • You have a set of operations that you want to do before delegating calls to the adaptee. You can use this idea to isolate data layer logic from the adapter and adaptee business logic.

Frequently Asked Questions

What type of design pattern is the adapter?

The adapter is a structural design pattern that converts the interface of a class into another interface to make them compatible. It uses an Adapter class that can either use composition or inheritance to delegate calls to the interface that it adapts to the target.

How to implement the adapter design pattern?

You have a target class/interface with an interface that is not compatible with that of the adaptee class/interface. So, the Adapter class will bridge the gap between these two.

  1. Create an Adapter class and extend or implement the target class/interface.
  2. Add a field to the adapter class that will keep a reference to the Adaptee object.
  3. Implement the Adapter methods and delegate calls to the Adaptee methods on the Adaptee field.
  4. Client should use the Adapter class passing the Adaptee object.

What problem does the adapter pattern solve?

An adapter pattern allows a class with a different interface to collaborate with code that expects another interface. For instance, you have an interface called Bird, and your application uses that to simulate a bird’s flight. Next, you want to add a Unicorn to it, but a Unicorn interface differs from Bird. 

What you can do is to have an Adapter that wraps the Unicorn and implements the Bird. With Adapter, the Unicorn seems like a bird to the application, and it calls the fly() method on it. Behind the scenes, the application delegates the fly() call to Unicorn.

<?php
 
//Target
class Bird {
    function fly() {
        echo "Bird is flying".PHP_EOL;
    }
}
 
//Adapter
class UnicorntoBird extends Bird {
 
    private $unicorn;
 
    function __construct($unicorn) {
        $this->unicorn = $unicorn;
    }
 
    function fly() {
        $this->unicorn->fly();
    }
}
//Adaptee
class Unicorn {
   
    function fly() {
        echo "Unicorn is flying".PHP_EOL;
    }
 
    function gallop() {
        echo "Unicorn is galloping".PHP_EOL;
    }
}
 
//Client
class BirdFlightSimulator{
   
    private $bird;
 
    function __construct($bird) {
        $this->bird = $bird;
    }
 
    function setBird($bird) {
        $this->bird = $bird;
    }
 
    function fly() {
        $this->bird->fly();
    }
   
}
 
function main() {
    $bird = new Bird();
    $unicorn = new Unicorn();
    $unicornToBird = new UnicorntoBird($unicorn);
    $simulator = new BirdFlightSimulator($bird);
    $simulator->fly();
    $simulator->setBird($unicornToBird);
    $simulator->fly();
}
 
main();
/*
Bird is flying
Unicorn is flying
*/
?>

Using the Adapter Pattern in PHP Today

Voila! That’s all about the adapter design pattern. Let’s have a throwback now. The adapter patterns take an interface and adapt to another incompatible with the former. It does so by using an Adapter class. The class it adapts to is called Adaptee, and it adapts to is the Target.

The object adapter, which is one type and the other is a class adapter, uses composition over inheritance. It keeps a reference to the Adaptee object and implements Target’s methods. Inside these methods, the Adapter delegates the call to the Adaptee object.

The article features an application that uses a JSONParser class which acts as the Target. When XMLParser comes into the scene, the application cannot use it because it couples to the JSONParser class. XMLParser being an Adaptee, needs an Adapter and the Adapter then delegates the calls to it.

This way, the application becomes compatible with the XMLParser, and that’s the adapter pattern.

Hopefully, you have liked this article. Stay tuned at FuelingPHP for similar content.

Books on Design Patterns

Want to learn more about Design Patterns? There are many great resources online. We recommend the following books for your collection as they both can teach you the theoretical and the application of using design patterns in your day-to-day programming. Feel free to use the following Amazon affiliate links if you’d like to purchase them and a way to support our efforts.

Design Patterns: Elements of Reusable Object-Oriented Software

Design Patterns: Elements of Reusable Object-Oriented Software book

This is the book that started it all. I believe that every programmer should have a referenced copy to this book at some point in their career. There have been many updates and excellent newer content through the years, but this is a classic. It still stands the test of time and is just as relevant for today as it was in the original printing in the 90s.

Check it out on amazon

Learning PHP Design Patterns

This is an excellent book to go beyond the theory and apply it to writing good PHP code. Learning PHP Design Patterns is published by the popular O’Reilly media company. O’Reilly consistently publishes some of the most useful reference material related to software development. They are known to provide materials that thoroughly cover a topic in a way that is simple to understand. I recommend this book to every PHP developer.

Check it out on amazon

Design Patterns in PHP Learning Series.

This article is part of our series of design patterns in PHP. We are going through all of the patterns and showing how they can help you build better applications. Browse through our full list of patterns below.